From bb89a659b39f498bed41a235f78fe58f902c94c6 Mon Sep 17 00:00:00 2001 From: troyyyyy <373071971@qq.com> Date: Tue, 15 Nov 2022 14:23:58 +0800 Subject: [PATCH 001/601] abduction with exhastive search --- abducer/abducer_base.py | 113 +- abducer/kb.py | 142 +- datasets/mnist_add/get_mnist_add.py | 37 + datasets/mnist_add/test_data.txt | 5000 +++++ datasets/mnist_add/train_data.txt | 30000 ++++++++++++++++++++++++++ 5 files changed, 35160 insertions(+), 132 deletions(-) create mode 100644 datasets/mnist_add/get_mnist_add.py create mode 100644 datasets/mnist_add/test_data.txt create mode 100644 datasets/mnist_add/train_data.txt diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 13e1f75..15badf6 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -11,58 +11,60 @@ #================================================================# import abc -from abducer.kb import ClsKB, RegKB -#from kb import ClsKB, RegKB +from kb import add_KB import numpy as np def hamming_dist(A, B): - B = np.array(B) - A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) - return np.sum(A != B, axis = 1) - -def confidence_dist(A, B): - B = np.array(B) - - #print(A) - A = np.clip(A, 1e-9, 1) - A = np.expand_dims(A, axis=0) - A = A.repeat(axis=0, repeats=(len(B))) - rows = np.array(range(len(B))) - rows = np.expand_dims(rows, axis = 1).repeat(axis = 1, repeats = len(B[0])) - cols = np.array(range(len(B[0]))) - cols = np.expand_dims(cols, axis = 0).repeat(axis = 0, repeats = len(B)) - return 1 - np.prod(A[rows, cols, B], axis = 1) + return np.sum(np.array(A) != np.array(B)) class AbducerBase(abc.ABC): - def __init__(self, kb, dist_func = "hamming", pred_res_parse = None): + def __init__(self, kb, dist_func = "hamming", pred_res_parse = None, cache = True): self.kb = kb if dist_func == "hamming": - dist_func = hamming_dist - elif dist_func == "confidence": - dist_func = confidence_dist - self.dist_func = dist_func + self.dist_func = hamming_dist if pred_res_parse is None: pred_res_parse = lambda x : x["cls"] self.pred_res_parse = pred_res_parse + + self.cache = cache + self.cache_min_address_num = {} + self.cache_candidates = {} - def abduce(self, data, max_address_num, require_more_address, length = -1): + def abduce(self, data, max_address_num = 3, require_more_address = 0, length = -1): pred_res, ans = data if length == -1: length = len(pred_res) - candidates = self.kb.get_candidates(ans, length) - pred_res = np.array(pred_res) - - cost_list = self.dist_func(pred_res, candidates) - address_num = np.min(cost_list) - threshold = min(address_num + require_more_address, max_address_num) - idxs = np.where(cost_list <= address_num+require_more_address)[0] - - #return [candidates[idx] for idx in idxs], address_num - if len(idxs) > 1: - return None - return [candidates[idx] for idx in idxs][0] + if(self.cache and (tuple(pred_res), ans) in self.cache_min_address_num): + address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), ans)] + require_more_address) + if((tuple(pred_res), ans, address_num) in self.cache_candidates): + print('cached') + return self.cache_candidates[(tuple(pred_res), ans, address_num)] + + + candidates, min_address_num, address_num = self.kb.get_abduce_candidates(pred_res, ans, length, self.dist_func, max_address_num, require_more_address) + + if(self.cache): + self.cache_min_address_num[(tuple(pred_res), ans)] = min_address_num + self.cache_candidates[(tuple(pred_res), ans, address_num)] = candidates + + return candidates + + # candidates = self.kb.get_candidates(ans, length) + + # cost_list = self.dist_func(pred_res, candidates) + # address_num = np.min(cost_list) + # # threshold = min(address_num + require_more_address, max_address_num) + # idxs = np.where(cost_list <= address_num + require_more_address)[0] + + # return [candidates[idx] for idx in idxs], address_num + + + + # if len(idxs) > 1: + # return None + # return [candidates[idx] for idx in idxs] def batch_abduce(self, Y, C, max_address_num = 3, require_more_address = 0): return [ @@ -71,34 +73,27 @@ class AbducerBase(abc.ABC): ] def __call__(self, Y, C, max_address_num = 3, require_more_address = 0): - return batch_abduce(Y, C, max_address_num, require_more_address) + return self.batch_abduce(Y, C, max_address_num, require_more_address) + + if __name__ == "__main__": - #["1+1", "0+1", "1+0", "2+0"] - X = [[1,3,1], [0,3,1], [1,2,0], [3,2,0]] - Y = [2, 1, 1, 2] - kb = RegKB(X, Y) - + pseudo_label_list = list(range(10)) + kb = add_KB(pseudo_label_list) abd = AbducerBase(kb) - res = abd.abduce(([0,2,0], None), 1, 0) + res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 0) print(res) - res = abd.abduce(([0, 2, 0], 0.99), 1, 0) + res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 1) print(res) - - A = np.array([[0.5, 0.25, 0.25, 0], [0.3, 0.3, 0.3, 0.1], [0.1, 0.2, 0.3, 0.4]]) - B = [[1, 2, 3], [0, 1, 3]] - res = confidence_dist(A, B) + res = abd.abduce(([1, 1, 1], 4), max_address_num = 1, require_more_address = 1) print(res) - - A = np.array([[0.5, 0.25, 0.25, 0], [0.3, 1.0, 0.3, 0.1], [0.1, 0.2, 0.3, 1.0]]) - B = [[0, 1, 3]] - res = confidence_dist(A, B) + print() + print('Test cache') + res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 0) print(res) - - kb_str = ['10010001011', '00010001100', '00111101011', '11101000011', '11110011001', '11111010001', '10001010010', '11100100001', '10001001100', '11011010001', '00110000100', '11000000111', '01110111111', '11000101100', '10101011010', '00000110110', '11111110010', '11100101100', '10111001111', '10000101100', '01001011101', '01001110000', '01110001110', '01010010001', '10000100010', '01001011011', '11111111100', '01011101101', '00101110101', '11101001101', '10010110000', '10000000011'] - X = [[int(c) for c in s] for s in kb_str] - kb = RegKB(X, len(X) * [None]) - - abd = AbducerBase(kb) - res = abd.abduce(((1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1), None), 1, 0) + res = abd.abduce(([1, 1, 1], 4), max_address_num = 20, require_more_address = 1) print(res) + # res = abd.abduce(([0, 2, 0], 0.99), 1, 0) + # print(res) + + \ No newline at end of file diff --git a/abducer/kb.py b/abducer/kb.py index d33be07..032731c 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -10,57 +10,104 @@ # #================================================================# -import abc +from abc import ABC, abstractmethod import bisect import copy import numpy as np from collections import defaultdict -class KBBase(abc.ABC): - def __init__(self, X = None, Y = None): +from itertools import product + +class KBBase(ABC): + def __init__(self): pass - def get_candidates(self, key = None, length = None): + @abstractmethod + def get_candidates(self): pass + @abstractmethod def get_all_candidates(self): pass + @abstractmethod + def logic_forward(self, X): + pass + def _length(self, length): if length is None: length = list(self.base.keys()) if type(length) is int: length = [length] return length - + def __len__(self): pass -class ClsKB(KBBase): - def __init__(self, X, Y = None): +class add_KB(KBBase): + def __init__(self, pseudo_label_list, max_len = 5): super().__init__() + self.pseudo_label_list = pseudo_label_list self.base = {} - if X is None: - return - - if Y is None: - Y = [None] * len(X) + X = self.get_X(self.pseudo_label_list, max_len) + Y = self.get_Y(X, self.logic_forward) for x, y in zip(X, Y): self.base.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) + + def logic_forward(self, nums): + return sum(nums) + + def get_X(self, pseudo_label_list, max_len): + res = [] + assert(max_len >= 2) + for len in range(2, max_len + 1): + res += list(product(pseudo_label_list, repeat = len)) + return res + + def get_Y(self, X, logic_forward): + return [logic_forward(nums) for nums in X] def get_candidates(self, key, length = None): if key is None: return self.get_all_candidates() length = self._length(length) - return sum([self.base[l][key] for l in length], []) def get_all_candidates(self): return sum([sum(v.values(), []) for v in self.base.values()], []) + + def get_abduce_candidates(self, pred_res, key, length, dist_func, max_address_num, require_more_address): + if key is None: + return self.get_all_candidates() + + candidates = [] + all_candidates = list(product(self.pseudo_label_list, repeat = len(pred_res))) + for address_num in range(length + 1): + if(address_num > max_address_num): + print('No candidates found') + return None, None, None + for c in all_candidates: + if(dist_func(c, pred_res) == address_num): + if(self.logic_forward(c) == key): + candidates.append(c) + if(len(candidates) > 0): + min_address_num = address_num + break + + for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): + if(address_num > max_address_num): + return candidates, min_address_num, address_num - 1 + for c in all_candidates: + if(dist_func(c, pred_res) == address_num): + if(self.logic_forward(c) == key): + candidates.append(c) + + return candidates, min_address_num, address_num + def _dict_len(self, dic): return sum(len(c) for c in dic.values()) @@ -68,70 +115,19 @@ class ClsKB(KBBase): def __len__(self): return sum(self._dict_len(v) for v in self.base.values()) -class RegKB(KBBase): - def __init__(self, X, Y = None): - super().__init__() - tmp_dict = {} - for x, y in zip(X, Y): - tmp_dict.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) - self.base = {} - for l in tmp_dict.keys(): - data = sorted(list(zip(tmp_dict[l].keys(), tmp_dict[l].values()))) - X = [x for y, x in data] - Y = [y for y, x in data] - self.base[l] = (X, Y) - - def get_candidates(self, key, length = None): - if key is None: - return self.get_all_candidates() - - length = self._length(length) - - min_err = 999999 - candidates = [] - for l in length: - X, Y = self.base[l] - - idx = bisect.bisect_left(Y, key) - begin = max(0, idx - 1) - end = min(idx + 2, len(X)) - - for idx in range(begin, end): - err = abs(Y[idx] - key) - if abs(err - min_err) < 1e-9: - candidates.extend(X[idx]) - elif err < min_err: - candidates = copy.deepcopy(X[idx]) - min_err = err - return candidates - - def get_all_candidates(self): - return sum([sum(D[0], []) for D in self.base.values()], []) - - def __len__(self): - return sum([sum(len(x) for x in D[0]) for D in self.base.values()]) if __name__ == "__main__": - X = ["1+1", "0+1", "1+0", "2+0", "1+0+1"] - Y = [2, 1, 1, 2, 2] - kb = ClsKB(X, Y) - print(len(kb)) - res = kb.get_candidates(2, 5) - print(res) - res = kb.get_candidates(2, 3) - print(res) - res = kb.get_candidates(None) - print(res) - - X = ["1+1", "0+1", "1+0", "2+0", "1+0.5", "0.75+0.75"] - Y = [2, 1, 1, 2, 1.5, 1.5] - kb = RegKB(X, Y) - print(len(kb)) - res = kb.get_candidates(1.6) + pseudo_label_list = list(range(10)) + kb = add_KB(pseudo_label_list, max_len = 5) + print('len(kb):', len(kb)) + print() + res = kb.get_candidates(0) print(res) - res = kb.get_candidates(1.6, length = 9) + print() + res = kb.get_candidates(18, length = 2) print(res) - res = kb.get_candidates(None) + print() + res = kb.get_candidates(7, length = 3) print(res) diff --git a/datasets/mnist_add/get_mnist_add.py b/datasets/mnist_add/get_mnist_add.py new file mode 100644 index 0000000..d05f477 --- /dev/null +++ b/datasets/mnist_add/get_mnist_add.py @@ -0,0 +1,37 @@ +import torch +import torchvision +from torch.utils.data import Dataset +from torchvision.transforms import transforms + +class MNIST_Addition(Dataset): + def __init__(self, dataset, examples): + self.data = list() + self.dataset = dataset + with open(examples) as f: + for line in f: + line = line.strip().split(' ') + self.data.append(tuple([int(i) for i in line])) + + def __len__(self): + return len(self.data) + + def __getitem__(self, index): + i1, i2, l = self.data[index] + return self.dataset[i1][0], self.dataset[i2][0], l + +def get_mnist_add(): + transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081, ))]) + train_dataset = MNIST_Addition(torchvision.datasets.MNIST(root='./', train=True, download=True, transform=transform), './train_data.txt') + test_loader = torch.utils.data.DataLoader(torchvision.datasets.MNIST('./', train=False, transform=transform), batch_size=1000, shuffle=True) + X = [] + Y = [] + for i1, i2, l in train_dataset: + X.append([i1, i2]) + Y.append(l) + return X, Y, test_loader + +if __name__ == "__main__": + X, Y, test_loader = get_mnist_add() + print(len(X), len(Y)) + print(X[0][0].shape, X[0][1].shape, Y[0]) + \ No newline at end of file diff --git a/datasets/mnist_add/test_data.txt b/datasets/mnist_add/test_data.txt new file mode 100644 index 0000000..3987383 --- /dev/null +++ b/datasets/mnist_add/test_data.txt @@ -0,0 +1,5000 @@ +5236 2931 11 +7455 7918 13 +7743 9396 6 +8167 8516 9 +3767 674 12 +4307 4808 8 +1567 712 12 +2456 1692 9 +6328 7863 9 +3976 3765 8 +6323 7115 6 +1815 1123 10 +5468 4196 8 +5831 6752 1 +9228 6807 14 +5915 6729 2 +8708 5377 10 +8273 296 0 +7748 4928 4 +6034 6210 12 +8180 2248 7 +3120 3309 10 +9020 8743 12 +5098 377 6 +2250 6812 13 +3914 6356 7 +2702 5181 9 +5696 2223 8 +2195 180 8 +2781 5425 16 +7979 5795 15 +4131 6977 10 +8991 1086 9 +1079 951 11 +661 6684 7 +3787 7889 3 +9057 6200 18 +9940 2852 14 +2737 510 13 +272 6374 2 +5885 4255 10 +1589 4594 2 +5833 773 14 +2424 6619 10 +4735 9625 13 +6154 7079 15 +4230 1377 14 +5109 1627 9 +4305 9508 8 +6026 2372 14 +57 8286 2 +4416 9463 13 +5657 994 8 +2981 4606 3 +844 8821 11 +6753 123 6 +1208 6162 4 +4224 4101 18 +9620 6451 18 +1694 6245 16 +1839 4866 6 +4014 4947 10 +3118 6126 15 +5358 9134 3 +7338 7093 6 +4294 412 14 +8521 2730 9 +668 7959 10 +1449 6344 9 +6124 8961 13 +4792 8220 12 +8129 5908 11 +924 3021 4 +8036 2548 11 +4188 5587 9 +352 7596 11 +2650 3884 17 +7914 4714 9 +2550 7217 9 +6392 3430 6 +2646 6708 14 +7886 6113 8 +3214 2406 10 +4643 4611 1 +8380 869 11 +888 5329 5 +9881 1360 4 +8846 7688 9 +7544 3992 16 +4160 7801 13 +7171 5346 4 +2243 1519 10 +902 1143 11 +6803 5559 9 +9884 9667 15 +1654 7052 2 +7920 1158 5 +3363 3410 7 +9628 3453 14 +5068 6175 8 +3856 9818 9 +5802 4516 6 +8283 2309 8 +7869 104 10 +6402 2619 6 +2159 3962 8 +8761 3023 13 +8346 7497 5 +4870 3192 9 +6220 604 9 +5352 1175 16 +3829 6565 17 +1407 6472 3 +430 9987 5 +432 7073 5 +8268 9496 9 +5841 3554 9 +7242 9323 16 +8340 522 8 +4132 9330 14 +7574 6697 11 +4249 6726 2 +1757 2807 3 +5975 5451 9 +1052 7172 14 +9132 1564 12 +3112 4988 17 +2025 4231 11 +3182 7964 15 +7012 3542 6 +964 1069 4 +4094 3822 11 +9439 8595 0 +8422 9140 10 +6333 6012 6 +2626 4769 10 +2470 2927 11 +8978 0 7 +3858 3994 6 +6825 2344 14 +2322 7 14 +5219 2610 11 +7457 5752 7 +4010 5689 2 +2964 7951 17 +9891 4938 16 +7441 5229 11 +177 2536 8 +3751 2137 8 +740 1611 7 +4269 4415 6 +4683 9580 18 +1852 1321 13 +1957 7646 2 +791 2262 12 +1454 1087 5 +9459 6916 9 +262 598 16 +8440 7520 12 +4073 3672 11 +3327 2564 9 +1883 1769 10 +2375 8760 10 +3983 109 5 +9980 3147 11 +5835 8878 12 +2818 9638 13 +4368 4371 13 +7601 1008 1 +9669 6731 11 +6349 5205 10 +3274 3048 4 +2181 4721 13 +6389 2750 9 +8003 224 8 +468 2247 12 +277 1792 15 +5473 792 8 +1470 6188 15 +5837 4173 11 +8364 6004 15 +4216 2045 4 +7535 1652 13 +6046 4534 12 +3710 2537 4 +2366 4767 8 +7349 1671 9 +7068 6498 12 +477 6041 4 +8191 5433 14 +3109 5907 9 +5905 8939 11 +8212 5707 9 +3134 2509 6 +9573 759 16 +5300 3606 9 +4487 1712 7 +3104 9386 12 +7113 5523 15 +2601 5577 10 +9050 1091 13 +1278 7566 3 +3228 3916 7 +3243 9334 6 +8406 3745 5 +2806 6020 10 +6110 5791 1 +2008 6189 11 +6542 2302 4 +8593 1935 16 +8941 5669 4 +6420 2559 14 +2175 6294 7 +928 5399 10 +1900 4837 8 +8141 2549 7 +2782 8189 10 +7200 7547 14 +9655 6628 4 +163 9126 12 +7797 1194 12 +5080 102 14 +7434 4729 5 +4856 9835 13 +2812 2953 12 +9405 5866 7 +6827 6183 11 +2882 2307 8 +3763 98 11 +4158 172 11 +4024 8345 6 +6808 2749 7 +1183 1573 17 +3426 2907 13 +1695 7185 12 +6354 5404 15 +5241 6028 5 +7210 972 6 +932 6929 2 +7636 2158 3 +3885 2467 17 +5137 6742 13 +875 4831 8 +8228 4483 4 +5228 5319 10 +5991 5318 2 +8005 2228 2 +7899 7942 10 +9810 1791 2 +8145 8176 12 +2330 6422 13 +1220 7925 6 +5307 1333 0 +3954 9642 17 +1472 5680 11 +7937 2303 7 +4082 149 2 +3446 1460 5 +8584 3369 11 +8109 1670 14 +5153 3160 15 +2433 8200 8 +7261 1493 5 +3318 4899 4 +4922 2190 8 +8138 4107 8 +9523 8507 10 +5510 8234 12 +1838 4910 10 +1326 3552 12 +1717 2911 16 +7908 7202 7 +8170 3368 5 +2726 8874 9 +8977 5206 14 +1778 8626 8 +1381 1509 6 +3807 7140 11 +6633 956 1 +4738 2747 4 +9073 5396 9 +8260 24 4 +9183 4658 11 +1093 7010 11 +1480 9498 3 +3173 3815 7 +1276 5927 11 +364 6050 12 +7706 9817 8 +3982 255 7 +4474 94 8 +9762 1899 11 +2048 132 12 +2499 3414 9 +8557 6272 12 +8361 9739 2 +790 3702 6 +47 3179 2 +8272 2007 7 +2177 201 14 +4875 1309 15 +6912 4380 10 +5534 337 8 +5963 9434 7 +7644 6520 12 +9824 4565 14 +8686 8697 11 +1217 7949 15 +6851 6985 11 +423 236 4 +2082 9082 4 +5388 5351 14 +5728 4377 11 +2849 1249 16 +2153 2924 6 +5574 267 6 +6683 7827 10 +9346 6907 5 +3065 7807 17 +7871 823 10 +6939 9722 10 +7105 2866 12 +6695 3463 8 +2013 2694 10 +1746 1764 3 +9401 4745 5 +5216 3093 7 +2232 8502 14 +3838 6112 16 +1318 9979 8 +8728 697 12 +663 6778 10 +3051 3433 7 +6698 2206 6 +541 51 7 +6568 2639 12 +2599 1142 5 +6712 1176 1 +846 6450 15 +5140 5612 12 +5390 7205 4 +3188 5544 5 +1774 7817 8 +6084 9313 3 +9357 7661 10 +273 7404 15 +4098 5217 4 +8670 899 17 +7333 4475 7 +7390 8777 10 +8318 2135 8 +3299 7778 9 +349 121 7 +5932 7436 3 +2905 4907 11 +870 4426 15 +9444 3346 1 +8526 5762 2 +11 8063 12 +6485 2056 16 +1253 7001 6 +7875 9992 12 +5148 6051 3 +8727 9080 7 +7136 9194 14 +7005 3576 9 +4422 6784 14 +8844 3263 10 +8411 7861 10 +836 5466 8 +9234 3386 6 +1759 7383 16 +2616 9844 6 +5037 6992 9 +1661 2256 7 +5486 6790 4 +2825 8912 9 +5237 4016 12 +1300 4568 11 +8798 1522 7 +2984 5314 2 +5437 6332 11 +7588 3650 9 +7098 3846 13 +1534 2324 1 +4411 9211 12 +7848 999 11 +9196 3044 7 +8575 7099 9 +4115 7189 9 +9574 8356 15 +4272 3168 18 +2600 6310 9 +1884 6740 10 +1411 9630 8 +6248 3907 13 +4579 4580 7 +8368 2979 15 +1741 9984 8 +3756 4378 10 +1870 9634 0 +361 884 6 +7103 9558 6 +6037 6917 5 +2461 1056 2 +6448 2881 7 +4636 1213 3 +1292 2112 8 +2032 9857 11 +9575 5684 8 +9938 6623 7 +3547 4760 9 +9870 5330 8 +6101 1780 2 +9483 976 12 +8227 9878 10 +7158 6819 7 +4751 2784 6 +5551 7211 10 +8301 1782 16 +8573 8940 12 +3835 4612 13 +5321 4500 9 +9191 2597 7 +601 3385 17 +7639 4891 3 +5191 2087 4 +5243 2063 7 +7965 2464 9 +7990 4710 3 +2891 8174 4 +2748 7260 7 +8455 9111 9 +8849 5447 9 +160 1114 7 +1067 3819 7 +6799 5602 10 +9353 5764 7 +5786 3777 2 +4096 403 16 +5119 1943 8 +4136 8215 11 +2508 9997 10 +8112 4939 4 +4508 5252 9 +5771 1508 17 +1344 2529 7 +7606 2753 8 +3909 9482 7 +8712 9542 2 +1033 8211 14 +5536 9239 2 +7617 9636 3 +3932 293 4 +7793 8168 7 +5661 7966 8 +9418 6786 8 +2757 5740 4 +4238 2146 15 +4150 4924 1 +3628 4850 10 +7764 7773 6 +5088 3497 10 +3437 8385 10 +2797 5670 12 +6228 3573 16 +4349 8514 1 +878 7732 13 +5177 8554 13 +7972 7815 6 +8470 89 3 +8102 9046 4 +1681 3420 4 +9761 1801 9 +9410 5941 17 +407 6746 5 +8250 6269 16 +1908 2889 10 +9548 592 3 +5895 83 9 +1248 7421 12 +4736 2098 9 +6331 4858 4 +3920 5507 9 +3076 4277 7 +1679 2101 6 +9054 196 10 +8833 173 10 +6591 5283 9 +9570 1809 8 +7780 43 2 +9079 4785 12 +2449 8544 2 +7551 3898 8 +4578 3039 8 +7950 8048 8 +7825 3700 11 +6089 7165 8 +496 4918 18 +1571 554 11 +1184 9321 10 +1038 7838 1 +9771 7394 11 +8709 1643 5 +564 8115 3 +799 7816 8 +8447 8720 6 +806 3034 17 +9802 3840 10 +8477 2052 17 +8580 3126 7 +2286 3500 10 +2472 408 12 +2260 4457 2 +2212 1705 16 +3988 9308 11 +6292 6891 8 +343 4836 6 +1685 726 13 +6435 6299 11 +20 225 11 +4672 9589 6 +2058 5335 6 +2046 4185 5 +5415 1286 8 +5334 8108 9 +9171 5008 1 +495 4332 12 +2421 8016 1 +5308 8449 3 +9391 6078 11 +9608 1749 9 +4418 6222 3 +3564 8506 15 +3744 6401 15 +2975 9028 17 +787 6748 9 +6668 1252 11 +1133 2268 14 +8713 528 6 +3602 993 6 +4971 3193 8 +2196 7070 17 +2039 621 14 +7940 8233 8 +9839 1807 2 +9764 7903 11 +4726 6192 9 +8457 861 15 +7129 4264 1 +5047 2047 10 +2308 3984 12 +3174 6806 12 +7273 167 9 +448 2630 13 +431 1440 12 +488 6867 13 +2586 6709 13 +1313 3222 10 +4720 202 1 +1684 6239 6 +2005 7449 4 +6621 2414 9 +2621 1539 5 +4613 5517 7 +3790 2563 7 +7900 9456 3 +1446 1085 8 +9282 9514 7 +8067 2841 7 +5631 8375 11 +2105 271 3 +2355 6955 9 +2218 2325 11 +4295 3421 8 +8331 7796 12 +44 942 9 +4436 8061 13 +8315 6384 4 +8801 8785 6 +4810 9988 10 +2544 6136 14 +3478 3282 13 +9480 424 2 +9861 8783 9 +3968 5477 6 +6148 4961 7 +8271 5636 5 +952 9825 15 +2528 7063 10 +8432 8059 3 +7804 681 12 +2386 4770 7 +3686 2090 7 +2864 5789 9 +1227 3942 2 +4106 7356 10 +6870 7363 9 +945 797 7 +2892 2754 15 +9015 9713 16 +5224 3357 7 +6941 35 6 +2234 1026 15 +401 5659 8 +9942 3329 10 +6488 2578 11 +1790 3053 7 +669 7741 7 +2685 1427 13 +5485 4718 7 +5395 1950 11 +8045 7557 10 +338 7924 15 +4337 4539 8 +4497 9269 14 +705 7042 13 +8737 138 11 +8230 8739 15 +6545 414 10 +9086 8692 7 +7011 7718 16 +8623 4965 11 +3251 7322 9 +1331 6670 6 +1854 5956 10 +7368 2916 9 +3467 619 10 +278 563 10 +8865 3197 8 +7106 1012 16 +4758 5105 5 +6357 8762 11 +126 1750 7 +6630 5355 10 +5688 4299 16 +2201 9205 12 +87 6894 3 +8732 7037 6 +6453 4012 7 +3809 410 8 +9349 6925 5 +3291 2016 11 +1903 4442 9 +9709 9695 13 +8150 3991 15 +1776 4823 16 +9225 556 6 +4697 767 8 +6317 8609 16 +2009 2764 9 +5782 1622 13 +8711 5260 9 +873 1946 10 +6447 7695 10 +4030 2577 16 +4800 986 13 +7540 5078 9 +8254 6905 12 +5650 6186 13 +3458 366 6 +6362 5607 8 +1441 6325 14 +3868 6441 15 +5492 4435 6 +3638 8581 4 +8673 9852 9 +8942 2490 15 +3515 9887 11 +2957 2148 9 +5550 3106 3 +5072 211 6 +1599 7771 7 +3721 9594 8 +8022 5256 5 +1369 2129 16 +2334 8274 16 +7380 3215 9 +923 1927 5 +4013 3507 10 +9796 8413 9 +5042 9019 16 +9719 3206 13 +9505 8796 16 +3170 7104 3 +4846 6298 15 +6234 735 3 +82 6031 8 +1514 269 2 +2977 4921 9 +2974 6660 5 +6044 8299 6 +6643 1498 7 +3239 3563 10 +3915 7782 4 +9742 6911 7 +3760 7245 11 +5255 6559 4 +5844 9040 12 +7373 3340 9 +3532 5445 6 +9718 1634 8 +6514 3272 9 +353 1734 13 +5881 3006 17 +6679 5223 12 +6833 2875 9 +3585 5979 11 +1608 9189 3 +4292 6642 10 +6486 816 7 +3766 7092 7 +5889 4830 6 +13 7572 2 +7110 9559 9 +3486 9975 6 +6963 4923 7 +3078 2942 3 +5448 5576 11 +2871 7144 10 +2615 7003 9 +713 5469 6 +385 6137 9 +9122 1558 6 +382 3108 6 +1193 2712 4 +8240 3726 10 +2341 7561 10 +749 4699 7 +8107 876 12 +7528 7849 5 +1327 5871 18 +8490 231 3 +3633 4355 13 +8594 6351 2 +7318 9707 12 +5757 8827 18 +2820 8467 16 +7425 5637 5 +2513 716 8 +8417 3011 14 +8294 1537 14 +7772 1605 5 +6693 4876 8 +124 3209 13 +8443 3794 9 +6055 8025 11 +330 732 7 +5380 5700 11 +5058 8438 9 +5959 6919 16 +8999 3557 6 +2017 8389 1 +9998 5588 6 +8682 7080 9 +9460 3967 12 +7219 8870 9 +1239 9479 6 +265 7094 9 +2582 7812 10 +9681 1877 16 +150 6049 17 +3105 7016 10 +3058 5978 7 +15 2510 6 +6246 2959 4 +1120 7880 14 +3014 5518 6 +3629 585 15 +1875 9414 7 +709 3857 17 +5385 8175 9 +393 5450 1 +8122 2819 9 +471 8341 15 +8714 8750 11 +8852 4818 9 +5248 7669 7 +2438 7413 13 +9841 6946 14 +2990 1989 12 +7678 4547 8 +1623 2337 6 +1524 4719 9 +8858 4716 2 +367 8489 8 +8767 5653 7 +1418 3404 18 +6300 3185 4 +8665 2257 14 +8303 5706 6 +6324 9615 9 +416 3960 6 +8445 5918 5 +6671 2861 11 +8079 9989 8 +2026 1364 14 +7020 7161 6 +2081 8216 8 +3245 5113 9 +1874 4883 11 +2996 8531 5 +2208 2899 8 +9083 1423 12 +8688 7163 9 +1967 9255 14 +9250 2697 14 +5843 4354 7 +9587 2968 16 +9277 1649 9 +5619 5924 8 +1885 2210 7 +3399 9178 13 +8663 5676 13 +6285 8136 12 +7546 5204 14 +7201 7147 6 +9543 4974 11 +8660 969 7 +4239 4348 6 +7471 6744 11 +5774 3080 7 +8944 7007 8 +6471 9172 14 +4081 7641 15 +535 5144 13 +1476 8065 13 +6320 5075 9 +5691 8628 10 +2524 658 8 +8394 3655 4 +7085 5522 12 +828 3895 2 +9639 1083 5 +2956 405 9 +6106 6772 11 +8265 7097 10 +3091 365 8 +5127 3668 4 +7720 1548 9 +5325 7233 8 +1921 4139 12 +165 1383 8 +8119 6736 5 +9756 961 14 +8266 3353 9 +2378 4833 3 +2350 1515 3 +27 2306 8 +1084 137 1 +3825 6793 12 +5354 3785 8 +7395 2729 3 +2261 8365 3 +4510 3665 8 +1553 980 11 +4327 1737 5 +3128 6719 2 +9096 7821 4 +4981 2422 8 +5648 8930 9 +7857 9531 8 +9143 3169 5 +6626 1775 4 +9337 2020 8 +1025 1565 1 +1568 3428 14 +2856 5842 12 +568 9048 8 +6788 9526 9 +3758 6036 6 +8652 9618 12 +7941 7112 8 +8101 9258 10 +851 3579 3 +8835 1285 10 +9268 5160 10 +8591 3981 16 +2810 7170 8 +4126 4367 10 +9666 7736 9 +5138 4685 9 +4083 7473 11 +5441 6122 12 +6230 6053 14 +4044 8392 7 +5986 2166 5 +9826 624 2 +4032 2151 4 +5840 2283 3 +7456 7829 7 +2669 5677 6 +5879 7879 6 +5919 9708 13 +3974 1999 6 +4759 521 10 +1975 623 13 +2961 5007 13 +8822 8431 13 +3706 2708 4 +3219 3413 0 +3043 8588 6 +4798 9699 7 +6844 8671 2 +8217 731 10 +6675 3689 7 +4599 2258 7 +6489 5379 8 +4832 4929 10 +62 9812 12 +7184 8695 6 +3544 8207 13 +3711 3038 16 +7839 1370 6 +947 8460 10 +4064 4273 8 +6338 3030 7 +6511 2392 6 +6704 8113 4 +6433 7111 11 +3560 9038 6 +4589 1904 10 +8639 1664 10 +4121 1669 16 +1572 9489 9 +9847 4871 3 +4181 6193 3 +6197 8882 15 +8523 6280 9 +7858 5920 9 +6236 5301 5 +4496 5784 17 +2938 2385 4 +2179 5904 11 +332 6866 6 +2128 6634 4 +3003 2589 10 +1929 8811 7 +2971 6557 2 +8848 6887 15 +4154 5914 16 +659 9237 10 +200 591 11 +9249 8310 3 +2342 9259 11 +1045 2239 10 +6667 6984 15 +3832 9665 8 +9611 3681 2 +1616 1603 7 +6658 1906 18 +2278 3611 9 +2915 1006 14 +2094 5718 4 +8125 1596 17 +8900 7579 18 +8645 7231 5 +3934 461 14 +9712 6150 16 +7332 9041 10 +8751 1379 9 +7798 5503 12 +8465 8794 9 +3317 4315 5 +4755 9785 12 +6176 72 6 +9651 3339 7 +7591 579 8 +6969 2774 9 +274 1161 15 +6108 9725 2 +2126 9751 4 +2402 9307 12 +6211 1816 4 +2388 6910 15 +4034 315 9 +3107 1592 14 +7738 825 8 +1115 8030 12 +1473 7488 9 +2416 6567 1 +1017 434 15 +7495 7362 16 +7853 8415 13 +7320 9686 9 +1969 2460 11 +3830 9043 2 +2793 6430 9 +2588 4555 16 +3333 8370 10 +2923 9042 17 +8313 1893 15 +7933 9734 7 +3438 4056 6 +2012 8348 9 +8895 1563 7 +5792 7675 7 +5974 6115 1 +7257 7175 3 +3075 7691 17 +5649 7265 15 +6756 1075 8 +2215 7502 14 +8305 5891 6 +181 9297 8 +1768 8475 7 +1825 1216 16 +3270 4087 9 +2391 1704 3 +5621 6322 11 +1862 9438 5 +6168 7293 13 +6254 3680 1 +9302 7490 14 +2099 4522 15 +2515 3412 5 +6647 7835 4 +2145 1053 6 +7904 6335 13 +9275 7789 5 +8861 9159 9 +5386 3806 14 +4536 9094 15 +3352 7370 15 +1919 193 16 +6223 1601 10 +1500 1965 9 +562 7246 18 +6842 5998 7 +4521 7207 5 +2941 2594 12 +2847 2896 12 +9500 4906 6 +7724 3545 8 +9130 4915 11 +6085 1662 9 +4159 498 8 +4148 599 16 +8754 4331 5 +6090 8344 9 +2 5347 6 +3919 2795 7 +2117 2771 8 +8239 5230 7 +5565 587 15 +9929 7791 7 +9513 1677 10 +7994 9069 11 +504 1210 3 +3938 5702 10 +6371 8495 5 +4320 6283 6 +3394 616 18 +7703 3460 9 +213 8214 8 +4935 5537 9 +2848 4958 2 +9652 7668 13 +485 2428 6 +7777 2389 13 +2709 2038 12 +6082 5074 3 +9300 7323 8 +2960 2037 13 +1556 6336 16 +966 3004 11 +7766 2973 16 +5232 4358 10 +4552 6149 10 +6856 9014 13 +8949 2640 17 +1421 2842 5 +9426 5179 13 +4124 3496 8 +1127 3779 4 +5167 6421 5 +4009 567 9 +2590 4853 2 +5405 5444 4 +5389 842 12 +685 1725 14 +5701 6635 10 +3761 5455 3 +4357 1409 9 +8741 8745 6 +6843 7623 8 +2485 9511 3 +4940 5428 3 +7956 5218 9 +4694 8867 9 +7556 2854 10 +4470 8043 7 +4804 8165 2 +5935 6478 3 +7199 1808 9 +7806 7763 4 +3583 7023 9 +1985 7281 6 +9177 8918 10 +8091 8722 10 +3529 7751 13 +1271 2216 9 +1156 3667 14 +8669 3555 16 +2078 5622 14 +6079 6901 8 +3082 36 10 +7856 1691 2 +1675 6233 9 +3990 306 3 +8184 2617 17 +2542 559 12 +9351 9218 11 +8355 8123 10 +4090 6871 7 +6218 5131 12 +8678 8330 15 +1266 532 10 +6033 1021 13 +7936 6703 5 +4151 1102 12 +2779 6359 8 +3475 2417 3 +4638 3390 6 +7992 4478 10 +360 5947 9 +6103 2267 9 +8002 8317 13 +8643 1089 10 +5185 5035 3 +6426 7877 7 +930 8322 16 +2676 5970 2 +1745 8197 15 +5605 6913 3 +3558 5769 10 +1653 2329 5 +7134 1201 6 +371 2674 3 +5189 5422 9 +2182 7329 4 +6419 6118 3 +379 5402 11 +3337 3771 10 +3304 8583 10 +2487 3649 6 +9081 2651 7 +2928 3310 1 +7126 6329 9 +2585 3853 15 +4165 9726 10 +6551 3774 3 +3715 111 10 +2554 9077 12 +1112 4712 9 +7462 7402 13 +5571 4750 13 +2918 6829 3 +7532 178 7 +5157 6876 5 +6795 7477 7 +1868 4558 5 +1953 9047 7 +9856 5597 13 +2799 4086 11 +8795 9793 6 +2675 584 5 +9089 3546 10 +2115 7196 13 +9290 4911 9 +5834 4600 9 +5309 7891 9 +7634 1955 17 +5273 4190 4 +7538 2917 11 +8293 7218 7 +710 2613 9 +9488 9168 2 +571 5730 13 +2963 9266 6 +9293 2919 14 +3324 4948 16 +1618 9528 5 +3280 4287 11 +294 3743 7 +4408 6377 16 +3366 6158 11 +7935 9659 11 +3614 1845 9 +596 2921 11 +7911 8769 7 +2077 3230 6 +835 9203 5 +9670 8398 10 +8841 9804 12 +3699 4066 3 +4626 8611 8 +5944 8641 9 +8881 3522 2 +9935 90 10 +2069 9605 7 +3596 9355 10 +4932 5067 4 +1322 4771 14 +1479 8512 10 +618 2591 12 +1061 537 1 +4797 4117 16 +5643 7252 5 +6566 3285 5 +4661 1625 8 +8334 4141 17 +1373 1980 10 +6518 8126 14 +2431 3731 5 +6776 5071 15 +2429 718 10 +383 8540 8 +1720 2371 8 +1489 4114 5 +4290 4166 8 +2381 9736 14 +802 78 13 +9244 1399 0 +3811 6491 7 +4364 5504 8 +5275 3127 10 +974 2338 6 +775 8957 5 +4591 1810 11 +1268 1135 13 +6721 4855 9 +9070 1237 2 +786 5027 10 +6286 3972 6 +8256 328 13 +3335 7680 14 +1613 2140 14 +7995 1044 9 +9889 4291 7 +1400 8691 6 +420 6659 12 +8765 7325 1 +8816 766 13 +8403 6711 7 +5066 9710 12 +8603 7238 10 +1550 8975 8 +7701 736 11 +2547 9905 10 +6810 7799 11 +2304 3087 0 +1058 7025 18 +1391 7301 8 +1384 3927 12 +4801 5367 4 +6824 3231 7 +8001 6885 11 +9768 9816 9 +9697 386 9 +7282 53 8 +701 3833 8 +3199 7319 6 +7982 481 13 +6290 5827 3 +8672 2836 5 +1455 2249 13 +2277 8201 4 +1081 5744 17 +3255 1738 4 +4880 2131 6 +6586 7704 11 +4630 6858 10 +7331 8886 10 +7410 8879 4 +7041 5667 9 +3805 8190 7 +7580 9429 12 +8864 7756 12 +7027 9242 15 +589 4384 6 +6247 3589 16 +1023 3484 7 +1450 9055 14 +2336 309 7 +9609 9493 13 +5435 5773 7 +282 946 14 +751 5613 5 +6682 388 10 +9260 16 14 +5630 2766 7 +3142 3926 11 +3728 6015 4 +5666 8156 4 +8901 5115 12 +7365 5398 3 +9384 7719 10 +9380 9202 6 +2305 487 12 +463 3345 11 +3184 6414 12 +3240 5957 14 +9922 5465 11 +6800 7308 4 +9774 9360 6 +1096 6340 9 +6606 5884 13 +7906 4195 7 +3795 5207 8 +8089 9579 8 +3581 2163 8 +9616 7298 14 +845 2633 9 +288 7492 3 +9398 8800 7 +2430 8222 12 +4554 9807 8 +4339 245 5 +6549 5592 6 +5624 1461 9 +3676 7503 10 +454 8947 13 +3957 4839 13 +9581 3608 3 +5082 3847 4 +4222 6582 7 +4142 1570 7 +9299 457 15 +6404 9829 17 +7932 3937 4 +6492 858 10 +3770 6147 11 +9662 1043 7 +1727 8149 8 +1579 6595 14 +8292 4089 9 +8724 5257 1 +699 1595 10 +86 7268 14 +1464 8634 8 +378 1129 2 +8199 647 1 +9261 8482 5 +6899 707 9 +4816 3597 11 +4725 9516 10 +516 5535 3 +9296 3305 0 +292 1552 13 +3449 5903 10 +7216 5065 8 +300 958 7 +2821 8566 8 +3989 4023 0 +5010 4644 15 +7565 6490 14 +7222 380 3 +4122 1419 13 +508 7970 12 +6506 6243 8 +6465 3587 12 +8706 6054 10 +8563 6123 7 +8194 3064 8 +6385 3661 7 +7728 5194 6 +7693 6252 6 +8404 7340 10 +88 1533 6 +4741 6943 6 +8565 7428 15 +5476 2242 6 +6944 5061 15 +1721 7626 8 +6694 5540 8 +5412 5663 14 +6459 5135 15 +916 9937 6 +8295 6618 3 +4884 6454 9 +8517 1760 7 +9745 6474 8 +4744 3730 15 +5442 9720 7 +4003 1258 11 +2339 8367 6 +2442 1363 14 +690 1356 4 +6179 738 8 +7028 7463 8 +6583 8247 4 +8169 3349 13 +5860 2023 3 +5489 5628 11 +7684 1952 15 +3217 2958 12 +6714 7774 11 +5627 9186 16 +5497 9743 13 +1325 9978 9 +555 6364 11 +1970 5009 14 +3921 5787 11 +7855 4627 6 +8026 3129 6 +1351 9723 10 +1632 7530 10 +7467 6532 7 +3737 3749 14 +3249 2920 10 +75 3479 7 +8996 3659 9 +8118 5604 2 +8536 5023 5 +9561 9911 3 +8015 793 16 +9341 8154 5 +3079 9931 8 +2043 3436 6 +2293 2518 14 +4872 6990 5 +7760 4754 8 +4217 4268 8 +8053 8236 17 +8962 4519 13 +4950 691 10 +5197 3095 10 +6886 4481 9 +7866 9352 0 +9185 6473 6 +3187 5818 6 +5393 7915 11 +363 6023 5 +428 6342 4 +4668 8764 2 +2948 3155 9 +5212 3403 9 +5806 5100 9 +4617 8576 0 +1886 4490 10 +2883 2197 13 +291 5817 6 +258 2791 8 +7586 2312 11 +3945 9333 6 +3950 9830 14 +1615 1051 7 +5203 1702 9 +3122 5129 15 +317 3252 11 +8646 8219 3 +5732 5461 2 +3616 281 16 +2004 3613 8 +3125 6837 14 +1259 4633 17 +2667 4805 10 +32 5552 4 +7230 7819 12 +5526 3088 6 +4192 6523 12 +2096 9215 2 +8055 9917 8 +5186 6922 7 +7015 5031 2 +5222 8144 12 +9036 6587 15 +8733 8006 16 +7335 5868 15 +8376 141 8 +295 7489 13 +2985 9927 7 +4677 9449 15 +5162 5432 12 +565 4449 10 +8685 5753 13 +4369 7026 12 +1224 6382 5 +4789 4656 10 +6008 3284 9 +2755 6864 17 +3694 4878 4 +3316 1822 13 +883 9376 12 +5640 8541 14 +8505 9916 15 +8128 5383 7 +774 6834 12 +1225 2858 17 +2571 5470 0 +1350 8428 8 +5568 5937 11 +6505 2593 9 +1956 5141 4 +5500 4819 4 +8503 5614 10 +6481 795 6 +7149 8441 13 +1526 6264 0 +243 8182 16 +5742 789 9 +2679 8908 4 +2246 720 13 +610 6029 10 +3634 9163 3 +205 2292 12 +7548 517 12 +4979 2568 5 +631 8843 16 +8550 2670 7 +9078 2986 13 +7961 9368 9 +4756 342 9 +4588 7611 5 +4025 5000 4 +5349 7173 9 +3086 2496 6 +9289 8893 14 +9184 4072 10 +9509 762 5 +7133 5589 8 +1178 2967 11 +9468 2294 3 +3200 9966 15 +7800 5295 8 +5227 9530 10 +7336 6820 11 +3068 5180 15 +2732 2817 6 +4260 3903 2 +2656 4386 1 +9748 6902 9 +5832 4448 4 +5094 6495 15 +5235 7727 6 +1448 6318 10 +2962 9952 0 +935 975 7 +7922 3594 9 +9327 5045 9 +9154 602 8 +6889 5429 17 +7585 1367 9 +8157 1949 15 +1982 9819 7 +9124 3527 4 +6172 1835 10 +9428 6209 13 +7385 4625 2 +6730 8917 11 +4078 2822 10 +1546 2493 11 +5102 7752 10 +4028 219 12 +843 7614 11 +595 9994 4 +8778 9390 11 +5496 1581 14 +3562 3121 7 +8632 3328 12 +5481 3148 7 +8444 7555 5 +5943 4908 7 +2607 4250 9 +7558 904 0 +3066 2598 12 +4584 8624 12 +1297 2746 1 +3682 6883 3 +2401 5745 11 +9554 3408 14 +5853 3141 12 +6629 8997 14 +948 5858 8 +1659 2168 9 +5032 221 6 +4773 4896 11 +5527 3575 16 +6462 7302 10 +3113 4620 11 +198 3873 12 +2092 6250 2 +2557 750 0 +8325 9746 7 +9298 645 10 +1004 3171 6 +3002 2271 16 +4513 37 9 +8892 348 2 +2993 3204 15 +18 9219 6 +9065 9403 11 +9138 7660 14 +6976 7883 5 +1994 1826 1 +2763 8590 9 +4228 7629 11 +2053 93 7 +3161 384 13 +6862 882 12 +7116 6978 6 +4703 1711 5 +9007 9969 4 +8049 2010 6 +1390 6467 8 +8756 9780 16 +6553 10 4 +809 1198 9 +8278 5600 7 +9820 4208 2 +1311 2648 18 +2383 6242 13 +3720 6526 7 +4229 6080 12 +7372 6005 6 +4398 1265 11 +6547 7744 11 +6232 9153 10 +1789 4404 3 +9103 478 9 +1505 9850 7 +8543 1783 8 +4314 1136 10 +6791 2890 14 +1196 492 8 +6515 3658 3 +9515 69 7 +6935 8235 12 +5652 1894 9 +9209 9361 8 +1119 2833 14 +3872 3971 13 +1187 9475 8 +3100 2132 12 +7000 9875 9 +4982 2141 15 +8661 7072 8 +3111 8637 13 +3904 6848 3 +5525 5725 8 +965 1887 13 +4281 4356 5 +9569 5563 9 +5980 5323 1 +7664 4874 13 +2886 4059 9 +7366 6966 10 +7952 6528 11 +7479 1932 5 +5852 222 7 +984 1580 5 +266 100 14 +6555 5556 12 +1628 7968 6 +727 5553 4 +877 8515 14 +1434 4776 1 +6171 7750 10 +1641 8757 9 +5269 728 11 +8221 3359 0 +1413 7864 13 +5988 3018 13 +7519 2361 12 +1335 9214 11 +7454 6603 13 +2605 5634 9 +5971 5424 18 +9013 9728 9 +1402 4465 6 +7017 9683 10 +8171 1891 5 +7232 7062 1 +9549 7735 9 +4849 8289 9 +9248 5685 7 +4688 4041 11 +7159 6202 7 +2872 2843 11 +5420 1185 13 +1538 9828 5 +2567 9197 15 +6056 8225 10 +820 9845 7 +8195 1889 3 +8992 8834 5 +3010 5361 4 +3543 2202 8 +4634 6821 11 +4628 8658 1 +4815 1066 10 +7440 8542 6 +4074 1850 9 +4642 3336 5 +3878 8662 11 +5583 6934 10 +9024 247 11 +3220 6613 11 +2935 9052 8 +3150 9147 10 +2507 1417 16 +8693 4076 7 +1840 9744 11 +9267 8524 12 +4492 921 5 +3890 4992 5 +3154 7071 13 +1846 4285 11 +3325 4088 9 +7841 9859 10 +7501 6959 3 +5364 6143 9 +1346 259 13 +4288 3673 4 +3156 9088 14 +4541 474 11 +4423 9983 7 +2660 3481 0 +1320 7369 16 +1055 5426 11 +8857 472 14 +1064 9278 8 +6841 6718 9 +5196 40 6 +9967 5291 9 +8818 7178 5 +1766 4763 6 +1274 1162 10 +8297 8094 10 +5855 3061 15 +5888 1255 13 +38 6135 3 +4817 1682 10 +3466 2214 13 +4537 8862 4 +260 1686 16 +4293 9409 12 +818 9769 10 +4550 3851 10 +4702 6321 8 +5875 8529 12 +3424 5342 6 +374 9176 13 +9087 1116 11 +9631 4093 9 +4244 1420 9 +157 8856 3 +4241 7510 4 +3951 2714 8 +8518 7682 12 +4530 6991 12 +9959 4495 8 +8718 9684 14 +8909 2253 7 +8829 8231 5 +5939 7024 10 +8549 7195 6 +8896 8770 10 +8335 6119 7 +6868 6353 8 +1812 5231 17 +8070 9470 5 +8500 2545 9 +953 7674 7 +1937 7122 12 +5286 4343 6 +2701 3427 10 +3347 8776 1 +3315 2906 3 +6648 8208 9 +8555 3298 11 +1730 2121 11 +3047 4619 8 +5511 5049 14 +5946 7312 7 +9114 5114 12 +6330 4886 9 +4951 5735 6 +748 2478 13 +3755 8426 18 +1777 9827 8 +9823 7376 11 +9782 2925 11 +6952 110 13 +4484 1280 7 +2541 6207 7 +4605 3482 5 +7781 1157 6 +7989 8353 2 +4757 2377 7 +3975 2983 12 +1342 166 8 +4782 2840 6 +2505 4623 14 +4480 5288 17 +4211 6227 11 +1020 6846 9 +530 3865 13 +5108 7737 0 +8753 838 7 +3341 763 4 +3852 511 5 +1996 4806 7 +9131 2533 5 +834 8244 7 +5763 8866 10 +5983 2217 2 +4999 874 9 +3523 4340 9 +8527 3094 7 +3383 1794 6 +6739 853 10 +3344 3032 6 +8719 6651 2 +2604 1444 11 +8173 9477 9 +1993 9125 4 +8774 3498 12 +7387 7612 11 +8850 9640 8 +5310 9369 9 +1562 4428 9 +5755 8937 12 +7289 394 9 +5106 6569 12 +1003 5165 5 +3098 8020 8 +8080 9338 8 +1076 395 7 +3837 8875 6 +1876 5683 10 +3741 7139 1 +3250 8321 9 +531 8976 4 +63 9783 7 +9157 4119 10 +1898 8387 7 +334 2327 5 +6259 4972 1 +1633 1218 1 +5136 9923 7 +4828 3636 10 +9544 4338 14 +130 3654 11 +833 8690 18 +920 7884 10 +8981 4118 8 +9791 3292 7 +8352 1406 6 +7986 4471 9 +7749 3897 5 +6261 1753 7 +2199 8452 10 +7768 3692 13 +1689 7429 6 +7224 3891 18 +954 3137 13 +3541 1706 8 +7514 190 9 +1977 4045 12 +1531 1551 5 +9326 2723 11 +5584 9675 5 +7509 3603 9 +3097 737 7 +6219 303 10 +8959 4282 7 +2238 2041 8 +3012 9109 13 +7153 9245 13 +2203 1172 11 +2677 1301 10 +7867 9033 13 +4669 8114 7 +8967 3162 13 +2403 7655 0 +4707 215 8 +7651 4209 15 +9536 8973 5 +1130 3621 13 +3025 2636 12 +2080 9897 3 +8478 3928 11 +608 9075 5 +5954 6892 2 +7321 5034 8 +8350 9221 7 +4382 7417 12 +7907 7379 8 +2816 5913 6 +939 2665 9 +5533 9377 7 +114 6249 16 +2185 6424 0 +3561 5697 9 +7192 6798 2 +4138 7633 9 +1256 3513 4 +3077 4732 1 +1922 435 9 +2160 290 14 +5410 5132 6 +3232 4092 12 +2878 4067 6 +5118 4887 8 +9784 3684 13 +6962 739 5 +2504 569 4 +4043 7182 9 +1724 7206 8 +639 117 13 +9031 2634 10 +4691 6347 9 +3165 6981 14 +8597 538 11 +4952 1212 12 +2743 6035 7 +6782 3074 9 +7344 5012 7 +6212 8143 14 +4748 9538 12 +1851 4621 12 +4342 5969 6 +4967 8735 17 +2161 5338 11 +7649 2237 10 +7255 7967 0 +3115 3503 14 +6312 5063 7 +6818 714 8 +5655 7707 16 +7896 1913 4 +3707 6811 11 +256 4637 7 +8474 788 15 +9851 2281 10 +6860 6758 6 +5128 476 2 +1858 2384 6 +9115 3630 6 +6381 6878 5 +322 4975 18 +2724 4256 11 +1126 4361 7 +8082 667 12 +1958 4157 4 +1474 3049 11 +5457 8561 4 +280 7539 4 +3607 1991 6 +9406 1496 11 +5311 7044 18 +778 6809 6 +6797 8629 2 +7076 3172 8 +7330 8508 3 +5513 1818 6 +7587 5779 7 +2333 3492 8 +2139 5886 9 +2625 4060 6 +9314 1583 15 +9135 8140 5 +1329 8429 4 +3191 8050 3 +642 2929 9 +2631 4212 1 +4653 7174 10 +3688 8158 11 +9374 2897 15 +7582 8155 5 +4841 7249 5 +7635 4532 5 +1591 9359 5 +28 7316 4 +5407 376 6 +8873 4761 10 +5168 21 9 +9436 926 2 +2792 1345 11 +4491 5976 9 +8243 329 1 +2768 327 5 +4458 4053 11 +3780 5038 7 +4986 1597 17 +4827 3001 13 +2614 8905 9 +3775 3441 9 +6759 3254 10 +5087 5391 6 +2189 2036 16 +8922 1150 4 +2680 4099 11 +5306 230 11 +3973 2733 7 +4204 2395 10 +7593 31 1 +7357 9867 11 +3864 1511 4 +2555 5020 8 +440 1544 7 +2562 437 9 +1016 4129 11 +2556 543 13 +3024 8252 5 +3186 7107 17 +2759 8421 13 +6915 9306 10 +8894 5538 11 +940 9476 8 +9092 7424 9 +2176 1934 3 +8010 4515 3 +1349 2624 5 +909 7237 9 +7130 3360 10 +3493 7755 11 +7592 6745 12 +6144 656 4 +67 915 12 +6908 2777 5 +3262 9765 14 +4615 3069 6 +640 5487 3 +540 3377 9 +3031 3588 14 +8532 2354 4 +7887 4366 3 +7823 8446 14 +9714 9879 0 +5890 7562 9 +3762 6986 13 +2773 8596 14 +4201 3948 7 +8205 2785 7 +1323 7605 11 +4254 6932 10 +8488 5899 1 +1028 957 6 +5671 8535 9 +324 5573 3 +546 9910 8 +84 3264 9 +2710 4391 14 +4560 3703 11 +6724 2119 15 +2657 3823 2 +6580 6524 9 +8017 9527 9 +8257 76 10 +5509 8832 8 +5532 4717 8 +2503 8648 4 +4989 4061 16 +4968 2365 16 +6650 4528 12 +2575 9590 8 +3442 3491 15 +6121 2066 13 +97 8242 15 +3642 3566 5 +7830 480 1 +931 3645 9 +8369 3308 11 +997 8110 7 +7901 5292 10 +9658 1836 7 +3017 627 13 +3740 4563 4 +7405 8647 7 +5041 4169 9 +2469 439 12 +9264 9224 4 +3326 7464 12 +8589 863 6 +9222 890 4 +3320 333 6 +8196 3176 8 +5408 5081 4 +4054 4183 14 +6830 959 11 +9907 5809 6 +9831 6751 6 +2142 6817 17 +4893 3595 9 +1166 6360 10 +8610 3313 12 +4360 2991 8 +7494 4402 6 +4868 8427 8 +8763 9627 6 +9336 7569 9 +2316 9644 8 +8038 1097 6 +2744 3746 11 +5836 2113 13 +1803 7589 7 +9478 4311 8 +6690 6205 7 +5578 7123 9 +7177 6504 7 +1393 1811 7 +8683 5829 4 +6792 6617 14 +2672 6700 10 +4388 71 6 +8898 1642 6 +8934 5948 14 +3970 5854 16 +929 5739 3 +8408 9619 16 +9200 8604 2 +7445 6306 14 +1057 4399 12 +8793 9238 5 +3637 7571 16 +3776 1503 8 +6367 1221 9 +2332 8275 12 +6680 8954 5 +8955 4240 18 +4453 5316 8 +3887 6576 15 +4596 381 8 +6099 3119 5 +5378 4031 11 +1435 9674 10 +1992 3319 17 +7983 7359 5 +1246 6558 6 +4147 9129 3 +8687 5375 15 +7805 5717 10 +1945 539 3 +613 5164 11 +5958 6142 11 +4529 8062 10 +4959 9545 5 +6487 4498 16 +1236 8569 3 +3520 3287 15 +4822 2863 17 +8014 4234 6 +9928 1035 10 +1095 733 12 +4246 636 15 +6030 6116 6 +6428 4036 1 +4362 2970 13 +8407 5741 7 +9432 169 13 +9892 4583 13 +6445 6979 1 +6801 8574 11 +64 1525 12 +9563 2173 12 +9407 973 7 +8868 8607 3 +4252 7573 13 +5922 4303 6 +5110 912 10 +7082 2379 8 +693 4451 10 +7679 3041 14 +6898 5625 11 +3267 455 3 +6276 5333 10 +3842 1587 15 +9442 1576 9 +6710 1873 18 +1452 8752 9 +747 6125 4 +1907 1892 0 +6610 8586 10 +4120 30 6 +4232 9471 5 +8627 548 11 +4055 1261 2 +216 7013 5 +8746 4997 4 +4577 8826 13 +4319 2445 14 +2511 3791 12 +4812 9995 4 +4654 469 12 +4681 5999 16 +8033 1426 7 +892 9974 6 +3571 2623 7 +1040 1160 5 +4346 5575 15 +2719 9676 10 +5459 4485 7 +7060 5873 9 +2937 7228 1 +4325 1287 17 +7168 6217 2 +4671 4309 17 +438 4137 15 +7511 6949 7 +5962 978 13 +7699 8721 2 +6238 2855 13 +6410 1963 12 +4004 6904 11 +6614 3935 8 +6226 4289 5 +3036 9606 11 +5013 4859 2 +3470 2803 6 +3013 6743 1 +5175 7396 7 +6253 2314 14 +5332 5183 14 +5654 49 11 +4561 6018 15 +847 9319 12 +2475 1575 6 +6117 6494 3 +5847 8889 2 +5599 6087 11 +7560 1542 8 +9904 4571 8 +6244 5490 6 +3375 4796 5 +3055 6343 15 +5865 4278 0 +3164 5673 6 +8681 3662 8 +3490 5711 9 +7317 4164 3 +7381 9388 1 +7397 3600 7 +7507 3266 1 +7236 4852 17 +9506 8246 11 +6923 5867 5 +9037 4134 9 +4033 8958 8 +4507 635 3 +4607 527 14 +3456 2299 5 +9284 2183 8 +927 4191 4 +4572 4944 10 +1316 4352 4 +6231 678 10 +9946 7893 4 +7278 2075 12 +9012 9706 6 +3506 4421 9 +2662 4444 11 +7485 6564 3 +500 6781 3 +6151 2653 8 +9693 7226 7 +1529 6997 8 +3705 7740 11 +42 5272 6 +3518 2725 7 +3601 3218 7 +8935 6771 15 +9213 6896 14 +9253 894 7 +5411 5381 8 +6155 3591 10 +7466 5590 7 +7276 5672 16 +2565 66 13 +4235 9324 10 +2552 7834 12 +1154 3955 5 +1631 9772 10 +6702 8324 2 +6190 5353 9 +9312 6109 8 +4917 2951 6 +6339 6869 8 +3784 1799 8 +905 6201 2 +2255 399 7 +1680 113 13 +8824 2844 13 +1655 5906 16 +9416 2280 12 +5134 7873 5 +2171 2435 1 +8311 5279 15 +1968 5872 9 +2360 3152 7 +3237 9291 2 +9303 3889 11 +4326 2024 9 +9187 8614 8 +9270 3469 10 +7061 4701 18 +1665 3879 13 +1392 9420 9 +5593 5373 9 +3717 5646 4 +6375 4213 10 +9400 8058 6 +3362 7670 12 +6760 5149 2 +4646 2865 4 +1609 5463 2 +3867 2596 2 +2103 287 9 +4110 6773 3 +2870 3622 15 +6442 105 17 +3978 4006 7 +7169 3685 8 +4943 6164 9 +2824 5746 1 +6098 1214 8 +2057 3537 11 +3146 3370 7 +3411 3144 15 +6893 8481 6 +9100 646 5 +8192 1805 12 +1182 9740 15 +503 4108 7 +1398 8899 17 +7486 7537 2 +5997 6663 12 +5810 4431 10 +8869 5090 7 +6747 2432 11 +9990 3265 7 +7962 2711 15 +2162 9865 5 +77 5644 10 +6550 7811 7 +552 7250 3 +2466 4557 12 +2241 6789 6 +2089 249 11 +6664 4005 4 +6460 5569 12 +913 6479 15 +8799 8950 3 +2546 2535 11 +8162 6529 7 +871 7360 9 +4595 2751 7 +2348 4734 5 +4544 6948 5 +3512 4199 7 +3941 7733 10 +1007 6548 13 +665 4991 13 +717 3987 8 +1820 7977 3 +2244 2319 13 +4175 1530 15 +922 3769 5 +2313 2205 13 +6010 1046 7 +8723 4174 18 +5062 9900 11 +2830 1222 10 +768 6461 1 +1199 4753 14 +5942 232 8 +6921 5317 7 +1273 4953 1 +1347 2091 14 +2727 6358 13 +1310 357 4 +8863 1340 10 +7600 3302 7 +7663 944 11 +963 1372 3 +17 6678 8 +6611 8567 5 +6011 4403 3 +6735 638 13 +4015 3028 14 +8466 9991 16 +5092 9880 3 +1683 9700 5 +8717 1124 17 +5214 9702 8 +1880 1676 12 +2369 8513 5 +7554 5263 9 +1823 2543 16 +3550 7559 11 +6831 7621 6 +7767 9274 9 +9112 1520 8 +893 3056 18 +6045 9424 9 +3947 8092 7 +8451 8414 3 +4793 1747 12 +525 6777 6 +6940 4476 5 +8013 1879 11 +6466 1824 4 +5293 5502 5 +8378 2164 5 +246 2904 2 +5830 848 1 +4329 1733 6 +9716 6372 10 +5822 39 5 +9152 199 6 +6509 7624 15 +241 4186 9 +7266 9039 3 +3439 9231 3 +6221 182 14 +5188 4639 16 +7314 7653 10 +4413 134 14 +6722 3468 8 +2300 754 4 +3183 9272 14 +8585 6070 16 +7969 3674 9 +4336 8806 14 +2689 2367 11 +6749 7762 8 +108 6713 11 +59 9800 5 +4459 9576 14 +8166 3405 5 +7031 8004 1 +5883 3473 10 +6975 5781 12 +2952 1619 3 +4970 9393 14 +7444 61 16 +3664 8396 10 +3670 7775 7 +6599 2645 11 +955 5294 9 +9448 3471 8 +9944 4506 5 +283 101 5 +9809 9179 0 +6956 9694 17 +5945 6308 4 +8633 9358 1 +2673 1029 17 +6732 6924 6 +5400 572 13 +6002 9595 8 +1630 7927 8 +8985 6038 14 +9072 4987 6 +107 4419 9 +6620 320 14 +4128 2447 7 +6681 8046 11 +7860 2888 13 +544 8339 12 +4027 6439 9 +2652 5940 10 +5796 7128 12 +5931 3593 3 +3138 1336 5 +6400 1763 3 +1909 3389 9 +8906 6673 10 +1264 9770 9 +7461 6289 9 +8522 7348 10 +5104 2323 13 +1483 2263 10 +187 7253 6 +5897 302 10 +1740 7843 14 +6762 7352 12 +3461 9977 11 +4202 6394 14 +7290 5785 3 +8791 4263 12 +5446 3644 11 +3727 8306 9 +2809 7337 8 +7240 509 10 +4091 9195 6 +1502 4040 17 +6194 7958 8 +1697 2720 18 +3489 7527 3 +9985 5656 10 +8880 9107 10 +4429 644 8 +4651 9408 10 +7895 3448 12 +3646 7157 3 +3290 2070 10 +8807 1015 13 +6536 1905 10 +7045 6942 9 +4826 7576 10 +7285 7036 11 +5084 8164 5 +3882 6369 12 +5251 7874 9 +4180 58 11 +700 3331 7 +3570 4787 11 +2520 4973 11 +5816 5046 7 +3226 3786 1 +5595 9571 11 +214 8699 17 +9853 9030 6 +5440 9986 7 +4318 6685 7 +9201 5639 11 +5029 2409 10 +5803 7414 13 +8072 933 8 +1559 5201 13 +5548 1348 10 +5519 648 3 +6900 4678 13 +7787 5515 8 +8363 671 13 +1148 7480 1 +1219 813 17 +551 8729 8 +6594 760 6 +1293 3268 7 +4985 6282 7 +7868 2147 9 +369 4777 11 +8704 9924 11 +5992 1415 15 +7478 2501 8 +5289 4882 15 +7687 9656 5 +3739 7930 5 +4017 5560 11 +5690 307 13 +192 9945 9 +9276 2451 12 +7439 8972 10 +1032 3669 6 +4920 5438 10 +1063 3511 11 +8060 730 10 +6570 7888 8 +2838 5091 3 +580 7734 15 +4700 1528 10 +8766 3195 5 +7523 9503 12 +8031 9454 8 +3980 8069 2 +5024 2335 3 +3371 1137 1 +7564 9091 8 +4494 4867 8 +7705 7221 6 +4179 2900 5 +8084 1307 15 +9582 5419 7 +2213 609 10 +9499 9010 3 +1855 1302 9 +2514 3814 9 +5101 4236 9 +3007 8483 8 +7786 6850 17 +9779 8223 10 +880 7450 15 +9957 3966 16 +898 3181 13 +8945 9678 10 +6003 1394 8 +254 6262 15 +1586 1330 7 +2538 3083 12 +5491 4104 10 +1108 7702 6 +3713 9097 9 +6701 8803 5 +2479 9704 0 +4155 4722 5 +8296 1314 7 +8319 6738 13 +3042 4182 13 +7019 140 7 +8700 9557 17 +1507 8820 9 +6025 7297 12 +4889 7208 10 +1105 9815 15 +7795 3480 10 +4520 4153 6 +8599 5964 14 +6588 4698 6 +6334 5892 9 +1744 8979 7 +7446 8077 0 +3289 3297 8 +9139 9535 10 +8181 3089 11 +3964 3301 10 +8185 6534 7 +4489 3159 15 +7179 9624 9 +3464 514 7 +122 2595 14 +197 5083 11 +4387 8775 6 +6455 2155 3 +2581 7364 7 +1445 1303 2 +9286 8684 11 +7288 8657 9 +5686 2940 2 +1022 7978 12 +1438 3952 5 +2399 7065 10 +9315 2000 11 +9767 226 17 +2932 3742 3 +4865 9932 16 +5036 8983 1 +7957 1656 6 +5772 8450 4 +4665 5579 14 +1901 8105 17 +5953 8439 2 +5749 5698 12 +2287 9285 8 +9696 4452 10 +9750 3869 12 +995 1821 11 +2227 9021 15 +6764 9501 9 +8202 614 10 +268 1795 10 +577 1832 6 +1804 2071 4 +3690 7686 7 +8160 3735 5 +456 4251 10 +7119 4609 7 +2473 2980 7 +9280 8771 14 +3883 1488 4 +3569 3046 13 +460 3666 14 +6368 6277 10 +429 5615 10 +8932 2370 8 +3584 8153 2 +4002 3906 4 +4385 3354 3 +840 2740 10 +7043 4069 10 +9441 7945 8 +5823 4344 11 +8814 8133 12 +4614 9045 7 +8525 5498 14 +6350 6930 9 +4533 1940 6 +5002 1098 12 +8887 6379 4 +9090 2289 9 +3425 7529 10 +8998 9415 10 +1964 4447 9 +7422 5880 2 +9788 6063 8 +3845 5208 9 +5934 6689 6 +600 4321 15 +5312 1260 11 +8613 5123 8 +5893 4602 2 +1707 5760 4 +9757 1197 0 +856 6563 8 +7481 769 14 +4464 5608 11 +830 7176 3 +6995 8342 4 +6266 4434 10 +827 4466 10 +6699 8469 5 +116 1456 10 +7305 4178 7 +1864 5811 5 +2912 497 5 +8679 6859 12 +2976 8842 9 +9876 8096 7 +633 442 5 +7391 785 9 +4543 3836 15 +9564 6853 15 +2462 1073 7 +7921 8845 8 +9422 3998 9 +6804 8497 13 +6009 2776 6 +8261 855 4 +6260 6666 10 +2728 1974 12 +879 9540 9 +9836 3135 7 +8499 1243 11 +5494 3652 3 +2706 3781 9 +771 7534 15 +7938 2390 7 +4392 9292 9 +9343 859 13 +3198 1787 17 +7049 2180 5 +7809 1245 7 +841 1410 9 +4051 4664 9 +1094 6597 0 +1204 5995 11 +6016 5960 8 +368 5178 10 +6346 9832 9 +1151 7358 12 +3508 9512 6 +7761 1639 11 +2879 6271 8 +772 6593 4 +8262 7164 10 +7570 2107 10 +8081 7882 4 +8206 346 3 +7820 4373 4 +1319 1857 14 +6196 1202 13 +6059 3288 7 +6802 8163 4 +7432 7642 15 +9389 9466 11 +237 5539 8 +8839 9701 18 +7997 992 14 +1716 9776 13 +1739 8276 4 +7943 3939 6 +6386 4994 12 +4504 7568 5 +1173 4019 13 +4317 5692 5 +7620 3525 10 +9217 8876 6 +2608 4660 15 +7124 7632 14 +2620 3582 7 +7505 1715 1 +2453 7117 6 +5778 5281 1 +9018 8553 7 +4259 8124 16 +1431 2034 3 +3917 2846 11 +605 5297 14 +4432 5911 8 +7046 9939 8 +3054 2930 12 +4912 6138 8 +7452 3116 2 +5808 7059 14 +6411 8847 14 +800 3617 14 +2204 1180 1 +9519 6561 7 +2717 4802 3 +2837 1786 11 +9643 7946 4 +3381 5747 6 +703 2387 16 +2628 151 16 +6133 8773 4 +2804 228 5 +2611 1059 9 +5274 3443 7 +7828 5849 11 +1167 4926 10 +1696 7506 2 +7167 1484 2 +9256 4133 8 +5797 5586 16 +8203 6047 16 +2813 1139 4 +7279 5174 5 +7067 4375 13 +2111 8725 16 +2873 4749 5 +8146 2516 18 +4071 3900 5 +9921 3894 7 +6575 1941 10 +5142 8619 8 +1833 9556 6 +5916 4597 7 +4713 235 11 +889 7985 8 +7846 3130 6 +8885 9650 14 +6146 4860 9 +4503 4708 3 +837 7844 9 +2240 8263 10 +3275 3618 14 +1637 5193 6 +4493 9956 8 +1806 7802 8 +6083 4562 3 +5112 7681 7 +950 3859 16 +4052 7154 7 +8966 4624 9 +3114 2207 9 +7980 6440 4 +8068 427 2 +8051 5863 6 +9555 350 7 +3979 3296 13 +3139 1140 12 +1986 5737 1 +675 1645 10 +6397 8971 2 +8473 8007 5 +6696 1920 8 +9497 4397 12 +1019 1853 10 +536 3259 3 +9232 9053 10 +3881 459 9 +447 5738 5 +8178 4687 5 +9893 8600 3 +545 1936 2 +6496 4527 9 +6669 967 7 +6676 6872 7 +8943 8347 6 +73 433 14 +9795 3828 5 +5040 2902 8 +4000 1779 12 +6600 9430 8 +2405 8397 6 +6132 2500 4 +1317 7190 3 +7166 5694 12 +7912 2944 7 +8245 1371 10 +233 5629 10 +8159 2275 8 +4675 2349 8 +9622 1995 1 +5909 7609 8 +3514 6645 4 +2808 6624 10 +4659 1928 12 +8425 3057 2 +5813 9366 15 +2700 8298 16 +4472 982 8 +2558 7598 12 +9688 9247 6 +4570 6836 11 +5850 1071 10 +9539 9397 18 +6128 3850 15 +8148 239 7 +7533 566 13 +2587 6936 12 +2570 6341 14 +9254 9612 10 +5555 1678 5 +3037 4152 7 +1382 5759 5 +9715 50 7 +7917 4969 4 +5800 7156 11 +4693 6769 11 +3778 9871 9 +4026 9399 10 +5733 3943 5 +9199 1113 5 +5660 8476 14 +3153 3995 11 +1062 9395 4 +8391 8902 9 +4566 5731 7 +9534 2192 12 +7496 8715 10 +8463 8703 8 +2498 8838 6 +4172 2999 4 +465 2767 11 +3005 4795 18 +6531 400 8 +3896 8927 11 +8520 1429 13 +9553 3718 13 +4667 6577 15 +5912 2637 12 +1561 7832 5 +3256 458 10 +5130 6240 11 +741 9982 7 +3754 4135 7 +6519 9648 2 +3090 2947 6 +1 242 10 +7433 864 16 +3855 6305 7 +4903 5095 3 +5001 9792 13 +7747 9029 6 +4774 1281 6 +3040 3958 9 +8986 1848 8 +1132 7353 3 +9806 8667 15 +4936 8424 9 +9223 8213 9 +5464 7770 12 +1100 8484 11 +5966 5170 11 +3213 9150 15 +5977 8496 9 +9117 2138 7 +7162 206 9 +8232 9443 6 +70 9347 11 +7723 3440 8 +694 6160 8 +9490 8399 8 +6387 6370 9 +9381 5609 10 +7987 9672 4 +6826 8349 14 +8090 2412 3 +1916 2972 6 +2443 6319 9 +248 8085 4 +5581 2450 9 +9233 7415 7 +1491 6180 8 +3574 2880 1 +8883 8568 8 +575 1468 9 +3059 3590 12 +7919 1650 8 +1960 3820 17 +9158 7526 0 +2188 8872 8 +1771 6838 10 +1388 8323 8 +903 5006 6 +6863 3376 10 +5004 9123 6 +3499 1477 15 +9698 8255 10 +2526 8564 11 +2654 1942 14 +8587 2019 9 +4905 1828 5 +9208 5344 13 +4840 3358 9 +4350 6437 2 +238 8328 7 +6500 900 6 +3283 2358 4 +240 3953 8 +6607 2072 5 +5750 3782 8 +2123 1396 16 +5471 3734 7 +4297 2486 13 +7721 227 10 +3789 3808 8 +1074 6468 9 +6105 4454 16 +814 9960 10 +9908 6127 6 +5770 6787 15 +3834 9885 3 +1128 6598 8 +6304 6903 17 +3019 8759 9 +8651 3391 13 +7204 5221 13 +2320 1397 10 +5751 9084 11 +6725 2786 9 +8854 1674 4 +2106 3578 2 +2739 2612 9 +5416 3599 3 +6065 7055 6 +3524 8437 14 +6996 3733 10 +8705 396 11 +7326 6785 5 +2696 3993 16 +5099 5528 7 +1036 8075 10 +7710 8074 9 +6483 1189 6 +3382 7500 14 +4569 12 14 +4298 6443 18 +3447 4499 12 +3536 6540 1 +4258 1788 13 +5780 1549 7 +3099 1416 1 +7002 2436 6 +4980 9691 14 +3918 1361 12 +936 2731 11 +7998 4220 10 +7032 990 9 +857 3145 10 +1629 5059 13 +6297 2683 12 +5748 7066 6 +4443 9252 12 +3227 6716 6 +5305 5304 6 +5838 6765 8 +1385 4807 17 +6625 7039 14 +5709 8650 8 +7069 6632 16 +9447 5414 16 +1442 9281 3 +4304 4545 9 +4460 9588 12 +9537 7212 6 +689 6348 15 +7215 5520 4 +5821 5456 14 +85 1068 12 +7142 755 6 +8696 7100 7 +1118 1125 16 +4692 1843 9 +971 387 6 +8990 9165 15 +7442 5488 6 +2474 1699 14 +2030 5261 12 +7437 8087 8 +9491 1437 7 +7842 5641 7 +7698 1039 12 +9664 3175 3 +2116 4379 10 +8032 8326 9 +3505 4223 11 +9169 6897 15 +3949 8224 13 +776 4313 8 +8933 782 12 +5736 9550 10 +1230 9584 9 +1761 7291 7 +6839 3540 8 +3190 1338 10 +7947 3008 13 +4679 3293 11 +3509 2713 8 +8817 3444 13 +8279 573 11 +5086 8131 6 +3208 6081 16 +5340 9799 3 +8308 9102 7 +9970 6861 9 +911 4383 16 +8237 4511 15 +470 2534 11 +1593 9044 13 +3494 553 15 +2279 6522 10 +8419 1997 6 +7197 1506 9 +5070 1687 17 +917 3276 8 +253 8023 5 +1532 9596 17 +9455 7783 1 +4363 5139 9 +1487 5384 1 +6107 8911 10 +1584 9860 11 +2310 9049 10 +2736 4469 10 +5864 3180 10 +299 8135 16 +372 9127 6 +6677 1374 4 +9877 195 8 +402 9903 4 +6572 1366 8 +5756 5645 9 +9789 1644 6 +937 2136 7 +4610 491 14 +4218 4162 11 +8530 3472 17 +6589 5824 10 +7638 3675 3 +4791 2527 4 +2738 6378 10 +2802 7543 5 +6345 5894 11 +3863 1324 13 +6074 4177 7 +2494 5454 12 +8926 3612 11 +4888 6060 6 +6656 9144 18 +5951 588 14 +6167 664 14 +698 5767 6 +7145 1881 16 +7064 4406 5 +8994 4409 10 +7654 7306 12 +5572 3535 12 +5876 3548 11 +6499 2622 9 +5161 970 11 +9345 5198 9 +3238 4038 8 +2489 4372 12 +155 3110 8 +4075 5073 17 +7077 2644 10 +8464 7220 14 +515 5397 8 +9902 9364 6 +8782 250 13 +5163 9451 15 +5331 9484 5 +6391 7137 6 +9370 867 5 +725 8748 1 +9210 356 11 +6062 2887 7 +9920 2666 15 +9000 3395 13 +1990 5582 15 +3286 9626 14 +8430 3643 10 +7239 9525 10 +7712 398 10 +6130 9023 15 +6927 4945 9 +8855 2209 5 +4632 9790 5 +9331 2079 11 +3671 5182 15 +2949 4262 9 +6687 2051 5 +5394 3205 16 +9011 354 4 +7050 1354 9 +7757 7808 12 +960 9371 11 +7960 184 15 +9811 5812 2 +5521 6581 4 +6406 1700 6 +7406 5638 5 +4960 3158 16 +3586 4728 6 +9677 2457 4 +2233 6544 13 +5618 3407 8 +8307 908 4 +2364 1516 7 +2885 8606 8 +5928 1092 9 +5026 4359 14 +2682 3323 13 +2315 6224 2 +8461 6000 12 +9703 3624 2 +655 4187 10 +1467 3400 12 +9890 2772 14 +2913 811 8 +6705 41 11 +5356 6061 6 +3922 4851 7 +4829 475 12 +5681 7014 7 +1758 745 9 +4847 1651 9 +7553 7148 17 +8012 5280 8 +1785 4976 5 +8390 5930 1 +5722 2851 8 +734 2922 8 +9813 6408 5 +1433 9076 14 +3244 8602 3 +4990 9971 5 +8698 7412 9 +7284 7244 13 +4008 1540 13 +2602 9167 2 +868 3848 9 +4546 4964 4 +798 8601 6 +5566 7254 10 +2627 2632 3 +9741 6931 13 +4631 120 5 +9777 2823 12 +8434 2769 13 +6828 467 4 +3605 2618 4 +1978 3312 9 +2569 6988 14 +5239 7929 10 +925 1408 3 +406 3123 9 +6958 1247 17 +3457 8436 10 +4548 1380 14 +4877 3704 9 +8969 5981 7 +6513 6449 9 +6165 3729 7 +4214 5371 14 +6638 1179 6 +7006 8537 12 +9348 7090 6 +4587 7083 10 +6263 5044 8 +6073 9711 8 +5195 9350 8 +1517 7438 6 +6173 3679 10 +9181 7181 10 +176 3931 7 +6086 7685 6 +2603 5069 9 +5125 2346 7 +8612 5516 5 +6088 3096 10 +7988 9913 7 +1466 7435 8 +5374 4468 9 +941 7048 8 +2495 4145 10 +7963 1267 16 +3946 6185 6 +897 1718 12 +8808 4310 5 +3027 7826 6 +8099 2845 10 +1933 7619 9 +654 7916 6 +8241 2826 14 +6865 8828 10 +3246 6805 15 +2288 5368 3 +341 3201 8 +6273 9504 10 +4914 1131 11 +6755 7590 11 +4389 5018 10 +5453 276 2 +6327 9423 17 +4065 765 4 +8064 6181 7 +1914 9529 14 +127 8423 11 +1541 8989 12 +3374 4111 17 +6366 5054 10 +706 8371 18 +7881 5276 7 +5215 8251 3 +7248 6794 6 +9427 7186 9 +1728 4854 4 +7713 1663 16 +7769 7375 16 +2095 1223 7 +1910 702 12 +4517 7029 7 +744 777 3 +7256 3278 13 +8548 854 0 +1602 7583 11 +3521 696 9 +7096 9948 4 +8654 3812 10 +161 6596 12 +1306 2074 8 +5246 5972 12 +574 1203 3 +4365 2439 2 +7053 1362 7 +7662 1701 8 +9635 7416 9 +872 8779 14 +8071 1912 12 +682 1138 3 +1209 4730 13 +1830 8183 9 +7536 4937 0 +590 5987 3 +9362 8920 18 +373 1755 13 +1754 881 11 +6477 118 17 +9602 6571 10 +501 4913 16 +7504 9567 14 +7150 2756 4 +4189 3432 5 +3260 2326 2 +6157 1859 17 +1463 5989 9 +1798 6141 4 +4775 4205 4 +8605 2359 7 +7125 8676 9 +3177 7484 6 +4149 4046 6 +1897 5794 2 +7341 3866 5 +8270 2084 9 +1762 2690 3 +9108 234 14 +344 185 17 +3772 9753 2 +5815 891 5 +2483 1918 6 +9093 5313 16 +7229 4283 11 +1430 8787 9 +5366 7004 10 +1099 1577 12 +8694 523 4 +5266 5658 7 +3843 6182 2 +7315 6766 5 +3372 8314 9 +9118 8086 3 +4752 8823 14 +9649 9520 2 +55 1590 0 +3258 8539 7 +9465 9721 12 +804 2992 3 +5003 2681 11 +2351 5857 11 +2347 1453 7 +3748 8218 13 +8073 6652 7 +6145 5985 13 +8458 8582 4 +7870 4042 9 +8649 5776 9 +5277 3081 9 +8740 2707 1 +4479 270 12 +5247 9435 10 +5242 4414 13 +3854 7223 8 +5710 628 11 +7709 4514 10 +4652 581 4 +7384 4062 9 +1050 6543 6 +91 2362 14 +8416 6973 7 +9972 7602 9 +2908 3888 18 +1235 6365 8 +9006 3940 2 +2317 3455 8 +7483 1847 7 +9732 1404 8 +9071 5851 5 +3619 2110 7 +7040 4705 5 +2226 7779 5 +3379 9160 6 +493 657 6 +6727 1088 12 +1646 6444 1 +9032 9577 4 +2193 5580 16 +106 1624 9 +8804 3572 13 +8747 5270 5 +5541 2721 8 +5807 832 12 +2143 1042 10 +1288 4341 2 +3334 4674 6 +1018 9864 15 +9279 6945 15 +7759 9413 11 +6879 6665 8 +4335 6525 8 +5870 6216 5 +3212 6064 4 +5418 1748 3 +5950 6102 12 +9731 3143 8 +3124 3396 3 +5116 2454 12 +9863 451 11 +6881 6918 9 +7453 5668 6 +2742 526 12 +9025 9340 8 +9385 6174 11 +2502 4 7 +1030 4993 8 +6717 4324 10 +9541 1072 7 +4390 4881 15 +7120 2903 7 +3965 9943 6 +2018 6585 5 +9607 8008 13 +6309 5768 6 +7645 6723 11 +9858 4079 6 +641 6373 12 +188 489 1 +4401 6546 2 +5900 6019 8 +170 3495 8 +2703 6092 1 +9309 2684 5 +1155 415 9 +7399 8027 9 +1459 8400 6 +4848 7448 7 +7343 6640 13 +3697 5662 11 +9918 2380 18 +4838 653 8 +1424 8249 9 +9637 4018 10 +5220 1688 15 +9735 9363 7 +6288 9894 7 +8379 8504 12 +4103 9668 11 +3969 4542 7 +5085 570 11 +5529 2642 7 +5699 9641 2 +684 4445 9 +7696 4097 7 +9002 1948 6 +4347 6605 12 +9001 2722 7 +4711 9392 11 +2458 6686 14 +815 2876 9 +547 6521 4 +3831 397 14 +6967 6999 13 +1648 392 15 +5949 3553 16 +314 6480 3 +9166 2382 15 +8354 1915 5 +3295 186 7 +8360 9027 4 +9382 2540 10 +7409 534 12 +7837 19 13 +217 7658 7 +7408 8578 9 +3698 7209 6 +9128 9059 7 +7604 5674 5 +4334 8840 6 +1240 6556 2 +5343 6533 9 +8788 1703 12 +9633 8130 3 +5720 8327 9 +7339 7247 9 +7790 4824 1 +3625 6914 10 +1462 3999 11 +6972 5327 9 +279 142 4 +780 3817 5 +8731 7597 8 +4768 9332 7 +5462 6075 11 +9265 1535 1 +8888 289 11 +4662 2054 18 +9617 3963 8 +9240 5557 8 +5695 4455 8 +2108 1070 7 +6032 5192 11 +8916 4984 4 +6757 7690 4 +4844 5096 9 +304 9236 4 +2989 6434 10 +2539 5616 10 +8418 9212 8 +821 3307 6 +1343 1800 15 +560 9034 13 +6815 8562 11 +887 670 7 +2065 9074 12 +3062 5423 16 +4505 9914 12 +7194 5022 13 +5284 6206 9 +5982 7788 13 +6502 5166 2 +3429 45 9 +8884 9968 13 +8382 8903 3 +1736 934 6 +7599 6961 1 +9654 7894 5 +586 4820 8 +8620 9068 15 +2156 2418 7 +1841 1395 2 +7955 7577 7 +7999 1332 14 +5910 9934 13 +5376 2484 15 +822 615 8 +9578 1731 5 +9936 7643 13 +5290 2050 8 +5043 2691 8 +3635 3516 16 +3902 297 5 +3750 5558 11 +203 764 3 +7652 5620 16 +7304 7401 8 +2965 6463 7 +3406 8837 15 +6832 7146 13 +8533 8044 12 +9963 4039 8 +9646 2987 9 +2752 2910 4 +578 3417 3 +9926 9192 11 +4641 2561 8 +1469 711 8 +1793 135 10 +3844 9412 6 +2521 865 10 +9833 466 14 +6265 7180 11 +8459 938 4 +5145 7822 7 +7948 6655 14 +1436 5610 13 +4301 128 17 +7731 520 12 +8083 2231 12 +4170 4689 6 +8116 6057 8 +9586 3450 7 +9738 6007 11 +2397 2356 3 +7367 919 2 +3880 9156 11 +7973 7324 6 +5199 446 12 +3986 2857 11 +4112 2200 10 +8948 1206 12 +9568 2198 8 +6783 3488 7 +5804 9394 11 +9136 2860 14 +1238 171 8 +9402 2274 17 +3073 758 10 +8511 2311 6 +9925 8953 12 +9872 6431 5 +8964 4746 12 +7758 643 8 +1693 1428 14 +362 2671 9 +914 2491 10 +4198 4070 9 +5111 1976 8 +6874 5302 12 +8730 4037 6 +7765 6692 17 +7427 6438 7 +5360 4439 14 +3816 2869 16 +8179 6014 2 +4247 4433 9 +9521 6380 9 +550 7697 16 +4461 9752 7 +612 5169 6 +2832 9425 5 +9775 1289 11 +7047 6275 12 +3330 3140 2 +4772 1554 13 +6215 7499 14 +6970 4957 0 +5262 1279 13 +2783 1060 12 +133 2934 16 +2011 2641 3 +6423 5561 6 +9120 9492 5 +3221 4425 12 +6303 4280 18 +5859 7198 9 +482 6822 11 +8442 9996 7 +2149 7296 15 +6636 3435 5 +5079 8117 0 +4978 7451 13 +9632 5271 7 +3009 8716 10 +6376 4731 17 +5484 7423 10 +7671 3800 6 +4919 7270 10 +6152 7152 10 +2655 9822 5 +9146 4330 11 +311 7430 5 +9973 2229 12 +1443 7730 11 +824 3648 2 +9933 752 6 +9601 6857 3 +7852 3683 13 +5370 5765 9 +4966 7084 7 +92 9431 12 +9657 5952 1 +2167 4586 10 +7458 3997 10 +6129 7191 1 +9794 803 10 +452 1080 6 +6315 630 15 +5387 3314 9 +1283 3598 8 +5172 1831 13 +5240 4163 16 +9591 1465 5 +3609 753 10 +634 4983 12 +6527 8790 5 +5801 770 10 +9095 3708 8 +5011 9759 16 +6257 1636 9 +2939 9061 10 +2459 7469 4 +2506 6177 3 +918 8572 7 +2265 8638 11 +5617 7132 13 +3423 1034 7 +7746 3487 12 +8831 3452 7 +907 2532 7 +7541 8448 5 +6311 1494 9 +962 1169 14 +2002 5727 12 +4608 8480 15 +6816 4080 8 +7155 264 14 +5493 1358 9 +6706 8383 14 +4011 1842 10 +7578 1299 10 +3615 2114 9 +1743 112 12 +3663 2178 5 +4676 8598 4 +7622 2426 14 +6508 2006 15 +729 2649 6 +1719 6094 14 +3886 4302 11 +9849 9141 9 +4057 7814 9 +5326 3799 14 +7183 6052 3 +9106 2530 7 +8545 2003 6 +6405 323 8 +4477 9981 6 +2093 4077 9 +8248 8462 11 +4784 3351 8 +3355 4590 6 +9598 7637 8 +2853 1501 12 +9842 3959 6 +9379 194 2 +5064 1490 10 +3163 9175 11 +168 2658 5 +244 2775 7 +9680 7400 5 +6042 5926 9 +6662 2165 11 +8621 5187 5 +1600 8519 10 +1911 2437 7 +1578 2945 9 +7813 7549 15 +8792 2468 12 +3241 5143 12 +8910 8802 7 +8963 8288 17 +5421 335 9 +2055 6198 9 +7613 2152 14 +8946 8472 7 +7271 2174 5 +8668 9322 14 +5051 358 7 +9005 8435 4 +1770 9101 14 +5365 9866 11 +9063 3534 7 +6497 2894 2 +4684 9458 9 +2408 6512 12 +1585 2236 2 +5923 1560 12 +5339 817 11 +2909 2789 6 +8029 8734 7 +7021 154 8 +7470 4956 11 +3063 7350 9 +4123 7615 16 +7058 1497 13 +4207 4629 16 +4105 1257 2 +9058 7616 15 +3462 6661 6 +145 1518 3 +8980 6352 3 +9964 8281 6 +3632 3696 9 +2481 5968 11 +1165 8993 13 +3157 968 9 +9763 3167 3 +2127 4696 5 +7971 3393 13 +3281 9387 1 +6363 812 12 +7393 886 11 +9257 9227 10 +3392 8040 15 +286 1594 15 +4645 9026 14 +2693 6953 7 +8057 3015 3 +2321 1009 6 +1296 8054 10 +9901 1000 18 +1141 2638 7 +6456 2172 9 +1797 1304 12 +9653 2284 4 +8635 9941 13 +2827 686 4 +1447 6770 5 +5546 1241 16 +5254 9204 8 +8401 3242 7 +9433 9565 12 +251 9273 1 +9597 6187 8 +1117 5053 9 +9404 9532 15 +6006 5805 16 +3923 7845 14 +9717 1001 3 +1867 3577 3 +4047 4783 13 +3792 4765 10 +7160 989 11 +1781 8701 12 +8860 1352 5 +2259 2688 10 +1951 1620 8 +3913 6840 5 +9173 6814 14 +1726 6909 5 +2698 263 12 +1341 4144 3 +9164 9705 8 +849 3924 12 +2758 5017 17 +7264 4904 8 +6552 4243 10 +257 8103 14 +4573 6974 6 +4525 576 4 +3151 1191 2 +3211 7859 6 +22 2551 9 +6517 2031 6 +6823 8021 5 +4535 8556 11 +3862 4526 5 +1181 7371 14 +5443 1966 7 +9730 1414 15 +6396 5324 11 +4895 5345 12 +6398 1422 4 +4462 131 6 +542 1557 12 +8302 3653 11 +9585 1723 0 +1188 1401 7 +6095 7309 13 +979 8642 10 +7726 2811 4 +9689 1523 9 +651 2088 16 +5158 4300 8 +1041 5253 5 +3709 6114 9 +2699 9162 2 +7715 229 12 +5499 207 6 +6562 5016 10 +4486 9623 10 +7876 261 7 +4381 5790 14 +1837 1244 10 +4962 8011 6 +6998 3893 14 +7474 6779 5 +1389 7418 9 +8486 987 15 +7419 5458 13 +1146 7672 10 +4794 3839 9 +95 5126 8 +1658 9886 8 +7524 7850 13 +3722 5530 12 +4279 3533 6 +7785 1752 7 +9325 2955 3 +6964 9148 11 +8493 8035 6 +3224 7460 15 +7283 4686 10 +5449 5315 11 +9803 1582 3 +8320 1598 7 +2060 2291 5 +8409 4351 2 +582 4538 9 +9342 1365 5 +6641 3026 9 +7262 7910 5 +1090 7792 15 +8736 4221 11 +4237 2124 13 +345 3549 4 +6159 8282 8 +3759 6199 17 +2452 862 14 +2828 9469 11 +1492 5211 10 +6436 9679 15 +4257 9949 15 +484 8287 10 +9778 7131 9 +453 8412 8 +9600 1308 14 +2191 4592 11 +5704 3788 14 +4328 7584 8 +3072 3901 14 +1610 3631 5 +9787 5703 6 +3528 8742 10 +8405 3189 15 +9461 2035 11 +4113 7996 7 +5766 9518 4 +1513 2144 9 +650 8970 9 +860 2211 14 +8238 9552 2 +3657 2476 11 +2419 136 8 +8809 7275 7 +8559 4670 2 +6296 1709 17 +1614 7267 11 +2222 3933 5 +422 5369 9 +3459 1251 11 +4809 2664 7 +2086 4393 6 +1359 4167 9 +3538 336 18 +4603 4766 6 +1698 1521 11 +3929 8372 14 +9912 5993 1 +7313 2998 12 +2573 6754 7 +4270 6225 5 +3580 3691 12 +1773 6980 10 +9116 1588 11 +8453 1861 6 +6720 9216 10 +3592 1872 13 +9008 3416 9 +6268 3567 12 +3067 4901 15 +4892 2926 14 +5743 444 8 +7303 622 5 +7345 4559 4 +340 3454 6 +8491 3235 5 +9494 7411 7 +5015 8608 16 +1917 8552 9 +3397 756 11 +2154 5479 4 +7355 6469 9 +6229 1732 15 +5687 7342 3 +1959 4322 7 +5244 9450 8 +3271 721 0 +2413 1606 12 +8919 839 16 +7108 5245 8 +6161 6111 10 +6538 6425 12 +8592 7294 7 +5996 6255 12 +6884 662 14 +2834 6845 15 +8689 3431 12 +223 1305 8 +4206 5936 6 +9335 779 6 +2788 7522 7 +1668 7095 18 +6895 5679 10 +6608 312 9 +810 4084 10 +7292 8187 4 +7234 321 10 +6153 5209 16 +8956 5902 8 +1708 4934 6 +5050 8636 10 +7625 7382 9 +8859 6609 7 +9551 6937 4 +5121 3620 10 +8304 2273 8 +3803 3070 1 +722 2033 4 +4267 742 1 +3724 9193 4 +6043 1486 14 +5798 7974 12 +7114 8384 16 +9899 5984 8 +2914 7259 11 +983 7508 10 +8819 6873 4 +5173 5567 8 +4242 6627 12 +5406 148 1 +9760 7515 10 +2643 5337 6 +3910 2266 4 +2109 2997 4 +5734 8618 11 +4954 3559 10 +2420 2770 12 +3504 1121 9 +2659 3261 7 +9411 1827 12 +8359 1902 5 +9603 1037 3 +6880 8938 6 +7214 9421 5 +3539 660 10 +9572 9486 15 +8560 6291 7 +4161 4100 4 +9188 1290 12 +8547 8664 12 +7725 2794 1 +4265 3415 6 +5120 2272 10 +704 629 2 +2264 4869 5 +4657 9009 10 +3841 8258 12 +7033 2097 10 +5664 6214 13 +9354 5055 12 +4864 3944 4 +5788 4742 13 +4890 1262 10 +9951 695 1 +7953 418 2 +8264 7648 11 +4210 1482 15 +5233 3677 9 +5585 7403 8 +5359 3101 10 +7517 5990 1 +1856 6195 7 +5048 7640 16 +3434 4648 10 +9647 1547 4 +4323 2444 6 +8147 8797 12 +5403 5887 15 +9339 2410 0 +7865 4690 14 +6602 8362 3 +1987 9724 0 +4048 6091 9 +3911 9317 6 +7018 4501 8 +6715 4271 9 +4068 3210 8 +4274 4127 4 +7188 9562 15 +1983 4564 4 +9440 8707 2 +9220 9846 1 +6170 4743 15 +1337 2373 6 +5775 8343 8 +6601 5039 5 +5758 1647 13 +808 3604 10 +2027 6965 6 +6971 9485 1 +6413 3229 5 +1569 4215 13 +4739 1626 6 +8358 5258 10 +4085 4786 10 +5705 5190 16 +9318 5460 3 +715 1101 10 +8285 8534 16 +5601 2814 13 +5341 8768 7 +8487 4308 6 +2318 7269 0 +3398 4879 14 +2186 5298 10 +5542 9950 4 +6235 6393 18 +7377 3233 13 +1890 8259 11 +4996 5955 6 +3380 7753 7 +3801 9798 8 +7227 391 17 +558 8093 18 +6994 450 9 +7141 2276 8 +208 9629 10 +7659 8780 8 +8253 1988 3 +8000 4740 7 +6960 507 10 +8551 9017 4 +3870 6251 4 +3194 2995 10 +7581 8037 9 +680 746 13 +7087 6968 1 +4862 9119 5 +2028 9522 14 +801 5480 8 +2270 2040 12 +1152 6069 16 +305 4049 7 +3821 5089 11 +5549 2678 11 +2407 7836 11 +512 518 7 +7513 9843 16 +7683 6888 11 +9329 9814 10 +1339 3996 9 +8772 2734 1 +2936 8781 13 +4863 7784 9 +9271 7389 14 +819 5921 5 +1878 7121 16 +5878 3764 3 +4353 885 6 +7374 5409 7 +9507 8936 11 +8558 1149 8 +8571 677 8 +2583 7692 6 +5633 9198 14 +4843 761 17 +9182 9328 10 +9915 7803 12 +985 7512 8 +5603 1106 6 +441 2254 2 +7794 3203 3 +906 5545 11 +4512 1478 12 +3085 3071 5 +2297 9868 15 +9882 1425 11 +9613 6835 2 +2328 757 4 +8433 3757 14 +981 79 7 +7493 617 14 +4885 2061 3 +5761 7101 6 +4020 7521 13 +3 409 1 +1640 7075 12 +4582 9781 9 +6208 5287 14 +1031 9474 5 +9262 5234 14 +9821 8812 7 +9604 8615 5 +5107 1242 11 +5682 1973 13 +2566 339 9 +8316 8142 12 +4102 183 7 +9502 8052 11 +7286 9749 12 +8974 3342 13 +7595 2480 10 +6604 3225 8 +2704 6890 5 +6390 5028 8 +6139 6484 4 +5103 4400 15 +6584 683 5 +688 8492 8 +8134 7934 8 +9149 9766 10 +7673 5651 6 +1849 513 6 +2404 5642 5 +3451 6470 7 +6476 5721 5 +7739 8815 9 +9999 8644 12 +1110 8209 15 +3502 9840 11 +2170 1200 14 +1882 7909 10 +8097 4811 15 +4312 9004 5 +6920 620 2 +6068 8152 6 +4779 5898 12 +3387 4813 13 +2668 5093 6 +3311 6906 7 +5754 3338 18 +9311 1355 7 +7810 8078 1 +524 310 6 +4616 8041 15 +2118 8377 12 +850 3474 3 +146 8056 8 +6982 2512 11 +8494 2463 10 +5596 2455 3 +3401 4635 3 +5861 1378 12 +4655 5056 6 +2695 8744 13 +2029 6737 9 +8968 1065 8 +2187 6140 7 +5184 6926 14 +2225 6507 17 +9190 7742 6 +2519 7776 9 +8913 7711 7 +7542 4438 9 +6184 5171 9 +1765 3273 9 +4176 7552 10 +9365 6928 4 +5514 5825 5 +3517 3269 10 +6573 316 11 +1672 7138 6 +1334 2301 12 +607 637 9 +3701 5014 4 +464 1924 7 +8309 5729 12 +6612 5150 11 +1735 6058 5 +7984 9737 5 +4900 3824 10 +8630 9246 7 +7714 2357 4 +2130 152 9 +7054 6093 4 +7443 3977 9 +1177 8921 2 +1282 5856 18 +7476 5033 3 +9446 2901 6 +52 9295 6 +4219 1869 14 +1844 988 2 +7392 7386 9 +4226 204 6 +9758 7878 11 +1233 7892 14 +5719 8393 12 +2441 4306 6 +7472 7388 7 +2735 413 16 +5472 5151 7 +1767 9344 8 +8351 5543 8 +829 2296 6 +9283 8951 3 +9661 4551 8 +2982 9121 2 +4125 4203 12 +6639 5267 8 +301 8366 12 +3875 8373 4 +1386 5783 8 +583 1666 11 +5819 3712 12 +209 5777 17 +4171 6314 6 +9883 549 7 +9064 2073 9 +2898 2635 6 +7630 9060 5 +7420 9895 9 +3656 3300 10 +4942 8952 8 +8333 5147 6 +4473 901 4 +56 2933 10 +826 7754 8 +3000 3117 11 +7009 7981 7 +156 2363 10 +5594 8076 10 +4407 119 11 +4998 449 7 +1536 5882 9 +7310 9453 10 +9133 4524 6 +7346 147 8 +6024 8625 10 +7143 3277 15 +5154 9773 14 +6852 2440 11 +6416 5678 17 +5152 4058 13 +7300 5322 11 +8988 5826 7 +6412 1939 3 +6592 4581 12 +2868 4143 10 +9953 6616 8 +2085 7939 8 +5156 3818 1 +594 3136 13 +2497 8891 16 +7847 2120 5 +3714 7717 7 +8805 5077 14 +3530 5282 6 +9546 1357 11 +1527 4116 9 +9174 6741 7 +7700 8749 16 +9898 9467 10 +9673 8386 13 +7263 5159 4 +164 9375 14 +3236 6644 8 +1234 8066 17 +9947 7311 7 +8928 3223 11 +6191 5820 2 +1756 9206 17 +9645 1635 6 +4576 2715 8 +1405 7550 9 +7056 2434 5 +7491 1979 9 +1375 7594 11 +3892 1657 9 +8836 7840 6 +5202 9663 4 +3020 325 4 +7818 4724 12 +4574 9378 2 +4345 7051 8 +1412 3627 10 +6954 5 8 +9510 2692 11 +6516 68 7 +5598 6067 10 +3752 479 13 +8210 9288 16 +8485 1109 6 +2966 5869 18 +2531 7872 8 +5226 1931 13 +5474 174 6 +6313 9671 9 +9993 2100 5 +2044 5401 8 +7667 4001 10 +8269 8300 12 +4715 4673 16 +1275 6399 10 +7608 8120 4 +1250 6503 13 +3294 1010 11 +7897 4245 15 +9955 4955 8 +220 1215 10 +7926 1729 9 +5554 8374 9 +4284 8454 15 +5896 8965 9 +4814 46 7 +2629 6482 4 +9755 2718 14 +1049 8088 3 +5213 2796 12 +6554 3961 8 +2396 2448 11 +6947 1751 4 +2647 5495 11 +7575 5265 8 +7022 1888 8 +603 5417 10 +2411 9593 2 +9035 6849 7 +2125 1612 8 +9808 6446 11 +1164 7378 15 +4593 7074 9 +5348 3641 5 +2194 4063 12 +4622 7890 7 +1024 3826 9 +9099 3419 5 +5097 8337 10 +5362 1863 6 +4601 5146 11 +3207 1284 5 +2741 805 10 +9896 3303 8 +1186 8907 9 +3827 7287 14 +6774 672 7 +6983 2376 4 +5724 8987 8 +6501 4275 5 +3802 9383 8 +2798 2021 10 +1168 4427 7 +7610 9145 5 +4286 6077 5 +425 2368 8 +1270 8410 12 +9733 3768 9 +8924 4857 3 +3384 8106 9 +7885 4663 13 +4927 2787 3 +5874 6293 5 +218 5278 13 +7482 9930 2 +4394 2352 12 +1104 1566 14 +7913 421 2 +8982 4130 12 +4861 1865 11 +5828 4553 9 +5434 3725 14 +483 490 5 +1510 7975 11 +7627 179 10 +1962 8617 10 +6066 977 5 +1159 5570 9 +4933 4909 6 +8931 7607 7 +7118 7426 18 +5524 4410 10 +1475 7851 12 +5712 8579 12 +2716 125 12 +3033 5793 12 +2579 3253 9 +8267 6691 15 +8675 4995 6 +2393 7091 9 +1860 625 11 +4450 3476 4 +3367 3343 10 +6316 2895 15 +5693 4488 12 +7081 6535 12 +7465 5249 0 +5726 2988 5 +6688 1710 8 +6768 8813 12 +4456 9067 9 +6307 445 13 +8402 5436 9 +5933 6241 1 +6429 9874 2 +1621 9837 7 +7689 390 10 +4556 5965 9 +2950 3248 4 +2525 3483 14 +3930 9873 5 +8479 2251 13 +2517 5268 11 +1555 8755 5 +4604 7258 6 +9320 6933 10 +2049 1294 9 +5938 9599 7 +8789 2663 9 +6134 191 7 +4467 8104 13 +6875 8111 3 +4109 3810 8 +5508 2745 6 +4666 8468 2 +6418 6203 4 +9583 1944 5 +676 1984 9 +1054 7299 2 +4781 9614 10 +4022 6302 15 +8666 1607 4 +3660 7327 2 +3531 6427 7 +4949 8357 9 +8039 4225 11 +9104 4156 6 +5635 7650 10 +6457 1207 10 +8726 6579 12 +2831 8680 15 +6493 351 13 +6409 8018 15 +3678 4931 6 +9243 8960 12 +1512 1772 16 +1231 4799 9 +7729 5626 4 +7676 7089 14 +5303 4482 8 +6574 7563 3 +9805 4780 4 +5264 6281 4 +7944 9003 2 +6166 8877 17 +3373 3332 11 +5846 2353 10 +7854 5296 15 +4585 5478 17 +7135 8890 8 +81 1972 6 +9888 9180 7 +6475 2340 8 +8456 6539 15 +8336 5430 6 +411 784 11 +5714 2059 14 +9452 8914 9 +2394 1144 9 +23 8034 10 +2778 3526 13 +7518 5238 9 +8204 1153 10 +6270 8188 12 +9533 5967 13 +7034 5225 11 +2169 8923 6 +1432 9113 9 +1930 1002 4 +1145 1802 6 +8284 6040 7 +4437 8501 3 +8897 8198 11 +1077 4540 11 +9251 9207 12 +9417 7525 11 +2574 6432 8 +1981 3956 10 +991 436 11 +9170 2014 18 +3736 1896 12 +8132 708 9 +3029 4376 12 +2104 781 15 +8851 6989 2 +7656 8291 9 +6048 6017 14 +2252 9473 11 +1005 6 13 +4197 3445 4 +626 6213 10 +74 4706 10 +533 561 4 +7567 6355 7 +719 4695 8 +3905 26 15 +8121 8915 6 +519 2790 9 +6541 3861 11 +7905 3016 3 +275 6847 10 +4825 9958 15 +3687 8546 15 +1171 8 12 +4029 3556 9 +5929 1226 7 +4575 9976 10 +2235 5427 3 +1817 2374 4 +1107 1229 17 +8702 9566 12 +6104 8098 6 +1574 7708 3 +4200 3409 10 +3022 4598 9 +7251 5961 13 +3216 3551 12 +3035 7677 9 +6734 1871 6 +375 6267 12 +1481 949 10 +2801 6169 10 +6295 1673 5 +14 4193 7 +6560 7035 17 +7109 5250 10 +3871 4396 12 +4007 3365 13 +5647 4227 8 +724 3738 9 +99 5328 12 +5021 284 14 +318 557 9 +1195 2221 1 +8471 2224 8 +1205 5591 9 +5562 2560 5 +7127 5665 14 +3651 252 10 +9965 6458 10 +7203 2686 5 +6649 4261 13 +7431 1998 12 +3422 313 9 +3418 1813 15 +692 8100 6 +3052 9098 4 +80 6279 9 +8177 1895 8 +2285 679 14 +9472 6237 15 +8784 796 11 +4441 8738 6 +7102 4723 6 +7531 9838 6 +3626 2219 16 +2398 7516 1 +2477 5133 9 +4417 2133 11 +1690 794 3 +8616 5848 5 +6395 9105 8 +1866 4266 9 +2295 4184 9 +3723 6096 12 +2705 7545 9 +8538 4316 10 +1660 2400 12 +6097 2592 0 +7151 4021 3 +3876 4916 6 +1011 5005 2 +6775 4095 14 +4898 1170 14 +419 2471 7 +7475 4194 9 +673 8640 18 +5431 6796 3 +5531 9495 7 +1604 8853 7 +143 3693 10 +9854 6383 8 +159 7088 11 +158 2523 10 +2859 3196 9 +7665 1134 4 +9906 5901 10 +2062 5439 10 +7902 9419 14 +9304 831 3 +6951 6672 4 +2780 9062 4 +3849 3813 8 +1457 1543 7 +1829 9305 4 +6131 9316 8 +910 1925 11 +4420 4567 9 +1269 8677 8 +3402 6537 11 +1312 9909 15 +1122 7272 10 +347 2522 8 +3257 4233 7 +4424 4842 13 +1439 8509 10 +6654 9056 11 +3166 9547 9 +3133 355 12 +6022 1190 14 +4509 5973 6 +2762 2134 11 +3639 611 1 +8019 3178 2 +7459 389 18 +2800 9727 11 +7277 9457 8 +2584 2150 14 +2427 6733 4 +895 5200 4 +5606 7351 8 +1451 3719 9 +7295 3797 11 +5611 687 11 +4518 6120 13 +2064 7603 13 +6530 3321 10 +7334 1926 10 +6464 7307 15 +129 8622 11 +8388 4941 2 +6510 210 4 +597 2572 2 +6278 1328 8 +9051 6578 9 +2609 3565 11 +3783 6178 17 +6987 9517 15 +6646 5839 4 +5320 9310 0 +8420 1504 1 +6637 4168 5 +9 5122 16 +1814 4395 13 +6013 2943 5 +7954 8825 8 +9241 8655 4 +1228 6780 13 +1315 4963 12 +2001 9287 14 +2184 9226 8 +2076 2862 11 +3796 4618 8 +7086 5505 0 +8871 5124 7 +6156 308 6 +6256 8277 7 +2805 9235 8 +426 1295 10 +8395 8172 4 +7991 9786 14 +6072 8631 7 +1714 9610 18 +2884 1211 4 +3912 5632 7 +3877 1376 10 +417 6855 16 +7831 3388 7 +5917 7354 1 +9229 96 4 +2867 1947 3 +9066 4253 14 +8830 5363 9 +4834 5482 7 +505 4727 6 +4430 8186 6 +5117 9954 8 +9962 3279 8 +9016 9437 6 +4873 8226 6 +3640 3874 9 +9356 9560 8 +6204 8280 7 +9834 1713 8 +5155 1291 3 +2829 326 7 +6707 2761 6 +7361 7694 12 +5299 9481 14 +3477 4778 10 +4276 8498 5 +3773 7008 11 +8577 6039 13 +175 34 14 +499 4050 7 +9660 3060 16 +998 4531 8 +7447 2580 7 +6326 2760 16 +319 3202 12 +1403 2576 2 +2893 189 4 +5336 4446 9 +8229 1353 9 +2606 285 7 +5799 2230 5 +6615 2298 14 +4845 298 10 +5715 3050 7 +9367 8137 0 +6337 2423 10 +48 2122 6 +1722 4704 8 +1048 8193 13 +9155 5176 9 +6361 6417 11 +370 4405 16 +9592 5060 13 +3084 2425 15 +5413 1387 14 +139 2954 4 +4764 4680 7 +6950 8786 10 +5382 3378 10 +9263 7030 15 +9621 7618 1 +2015 7468 2 +3985 8329 13 +723 3510 2 +8047 9729 7 +4762 3348 13 +4647 25 3 +115 443 4 +2815 8656 6 +2765 666 7 +6403 1368 9 +9161 1013 17 +7280 7187 6 +9142 8095 13 +4709 1638 2 +5675 529 9 +6957 6284 7 +6287 9487 2 +7898 9961 6 +1192 8042 15 +153 5723 7 +9110 8290 11 +2946 9230 1 +6728 7666 13 +8528 4248 2 +8024 5372 13 +4649 7407 9 +5845 896 7 +5076 8028 13 +1163 8151 11 +2488 5713 6 +7716 162 7 +7078 2482 13 +1232 6657 17 +6301 6452 13 +4333 4977 10 +5475 4897 8 +1254 9085 6 +1834 4737 9 +1458 7347 15 +7862 9754 13 +4440 7398 8 +9690 4835 16 +4374 9462 13 +2220 9801 7 +33 7928 5 +3364 5877 14 +9301 3568 5 +8570 3465 7 +5512 8710 12 +7487 3102 14 +2282 1495 8 +4296 1174 4 +3103 4140 15 +2492 1082 5 +462 1796 6 +2465 7745 14 +6071 7722 10 +29 5483 1 +6993 1938 6 +5564 3234 8 +4902 6750 5 +5467 7235 8 +743 8758 7 +7631 2850 11 +7241 9685 10 +7628 7243 12 +3092 3247 5 +5994 2687 6 +3356 3860 12 +6021 4925 7 +502 9869 12 +866 5259 5 +3485 1263 13 +4682 1961 17 +2994 1485 8 +3350 9137 6 +2978 8139 5 +2553 6854 5 +3716 9855 11 +9294 6163 7 +2343 65 5 +8810 8995 3 +3623 2083 8 +9747 8338 5 +7038 6674 13 +506 9692 10 +4549 9862 8 +6076 5708 7 +7057 3306 5 +4946 7498 9 +9848 3045 4 +8510 1499 15 +6274 2102 10 +9151 4803 11 +996 3732 10 +3798 8984 16 +3322 3610 4 +6388 4821 13 +606 4650 8 +6761 9464 5 +7833 3908 10 +2269 5019 5 +2877 9682 5 +494 4463 12 +4930 7328 3 +4894 8674 6 +632 5547 10 +212 3132 10 +8161 7274 7 +5030 6100 10 +1147 5025 5 +4146 4035 1 +2331 1078 10 +4733 1545 10 +3647 486 15 +3131 9022 6 +4412 1617 9 +6590 5501 6 +60 9919 14 +1784 7647 14 +3804 6622 1 +3753 6763 10 +4790 7213 12 +8904 1923 10 +1047 6415 5 +5925 1027 4 +5057 9372 11 +7225 2874 7 +359 2839 14 +2835 7931 13 +6653 3149 16 +852 1272 12 +2446 8929 2 +2067 652 1 +3501 6001 17 +9797 2245 4 +331 593 11 +4502 6407 10 +6258 54 12 +5452 2661 1 +5716 4788 2 +1298 2068 12 +1014 5210 15 +404 8381 4 +4747 1277 16 +3793 2290 11 +7657 3695 4 +9445 9524 6 +6938 783 2 +9687 2022 4 +8009 5392 10 +5506 103 5 +5285 5052 6 +5814 5350 4 +2345 3519 17 +3361 3925 8 +7923 1103 17 +3899 144 9 +1471 473 6 +6877 6631 8 +1954 2157 7 +2969 8332 14 +6767 1667 4 +6027 1819 8 +4640 3747 9 +807 943 9 +8312 7993 7 +8925 9373 10 +3936 5862 12 +2042 8653 5 +1742 5357 9 +1111 4523 12 +7824 1971 12 +8127 7193 3 +649 2415 9 +5623 8659 4 +4370 6813 5 +7976 6882 7 \ No newline at end of file diff --git a/datasets/mnist_add/train_data.txt b/datasets/mnist_add/train_data.txt new file mode 100644 index 0000000..c6e404b --- /dev/null +++ b/datasets/mnist_add/train_data.txt @@ -0,0 +1,30000 @@ +55431 23531 12 +29016 31531 15 +39520 30760 6 +14132 1921 5 +51122 56131 7 +24589 34903 17 +42015 27060 4 +20862 49322 2 +20762 25455 8 +36075 50076 10 +10877 42191 12 +20496 46974 6 +20707 27977 10 +48960 41052 0 +46052 4949 13 +4330 22196 7 +7754 53585 9 +41766 50283 10 +7210 14485 12 +29904 1510 4 +59719 45022 11 +32652 55323 7 +32077 38468 9 +33652 40292 10 +43165 5662 8 +38260 35335 10 +41599 14084 11 +16767 13251 9 +57884 27580 7 +21975 30466 6 +14779 47883 10 +32616 44322 12 +54387 22157 14 +29999 10455 2 +33202 28358 8 +4756 42051 8 +37470 34165 11 +57595 38483 0 +380 57250 5 +43993 43282 17 +22267 36206 4 +43136 44117 12 +28771 12562 9 +43244 43962 8 +48770 42619 10 +1505 43783 11 +8215 44727 6 +46377 54619 7 +45319 59198 9 +35148 11900 9 +28401 876 16 +11831 8152 9 +36564 23159 9 +49279 41231 16 +36728 14193 6 +13403 1254 11 +7184 52226 8 +58365 16547 7 +4753 34892 11 +52062 18747 15 +42681 2335 4 +10150 6116 5 +53398 5112 14 +53823 34531 2 +43104 48943 8 +55059 19222 10 +11267 14419 0 +25647 47245 11 +17850 36152 11 +4856 6719 5 +19473 18670 13 +54518 24110 14 +24407 20806 9 +27272 14869 10 +37955 9926 7 +58147 34391 6 +59488 25007 4 +58412 28974 8 +40268 38791 13 +39714 30410 5 +54078 27720 2 +55633 35139 12 +11332 14571 8 +19028 6250 9 +51157 43626 9 +24402 40544 5 +20857 13423 15 +4505 24970 1 +41108 38902 5 +58994 1743 13 +50799 22331 5 +41603 27018 10 +45088 19433 10 +36639 55569 14 +47960 1718 4 +32301 42581 5 +6866 16757 8 +52193 53268 9 +36481 43355 13 +8518 20644 18 +9932 15815 6 +5562 45663 10 +58904 46134 9 +59200 54914 6 +39232 34716 4 +12434 528 9 +42919 52856 12 +24075 31156 7 +15980 26681 11 +30093 44925 9 +51282 54713 16 +24367 55402 0 +5672 55524 10 +2756 59208 12 +56670 40330 16 +29398 54104 3 +15702 2064 12 +44998 18660 12 +8268 25419 11 +23987 49733 12 +33084 52534 7 +43524 42290 15 +21912 39511 10 +18545 17825 9 +16743 42048 12 +33607 46986 6 +21567 50308 10 +31137 37677 7 +34051 1941 3 +1962 5139 12 +5501 15712 11 +56562 34058 9 +23828 55459 5 +38774 15136 6 +32197 51562 12 +38358 53658 11 +47994 23287 4 +42346 2726 7 +59977 35952 11 +38858 9793 15 +44883 8417 6 +48920 51375 0 +16214 38461 4 +33940 30527 8 +52844 52522 10 +29814 52624 5 +4573 18478 13 +39493 36097 9 +56471 2809 5 +45742 3341 8 +15595 54521 12 +40108 51491 0 +31318 219 6 +12290 6553 12 +4437 3026 10 +56965 13533 6 +41245 3781 9 +29261 34437 17 +24138 45217 10 +51818 45073 2 +53546 25842 5 +34703 1286 15 +1889 18509 6 +50695 516 7 +40064 7737 15 +45318 16097 10 +32481 39710 2 +30639 20598 6 +28801 1628 6 +19459 7175 1 +46322 37941 7 +34746 50391 11 +25412 50529 5 +54197 42727 13 +52292 58731 13 +13952 33742 8 +31887 25471 5 +2036 26631 13 +8836 51672 2 +59611 41069 7 +20316 54074 12 +4855 9887 4 +51053 4908 13 +24477 28891 15 +7573 19720 12 +22760 13495 10 +21370 30232 9 +27987 27197 11 +28934 49699 12 +18272 9181 9 +1991 35461 9 +20011 44066 10 +4070 51759 4 +50186 4039 15 +9758 3786 18 +45040 774 9 +12487 42012 7 +2795 23322 12 +16980 1561 7 +10770 39984 6 +13254 9355 4 +41030 57634 0 +31054 48788 9 +36966 51517 8 +24207 49688 11 +16847 29023 9 +28645 18193 18 +56910 5927 1 +39922 17516 10 +443 53792 2 +39638 38564 9 +54255 11419 10 +26623 28880 7 +36359 29044 4 +32971 40800 17 +56738 17915 8 +56618 32493 9 +45373 56552 7 +26269 5777 8 +49130 39096 18 +11421 4628 10 +50026 45981 4 +56208 26780 2 +32913 58485 10 +59011 30905 4 +3746 34606 11 +29130 35040 9 +47957 4282 8 +5044 56016 10 +42587 31708 10 +48884 23695 5 +50754 38921 16 +56589 28371 8 +13943 35671 4 +11502 7837 2 +39205 49947 14 +24522 51792 11 +21857 17266 4 +10815 32631 13 +14180 43984 6 +23336 34161 12 +28810 51523 13 +2314 45726 7 +29890 43579 13 +27407 43490 1 +27638 16458 1 +46569 42394 11 +1642 50860 14 +2044 28036 10 +49307 6130 10 +55249 43594 9 +18645 47559 7 +34398 11414 13 +10236 28091 6 +16939 29986 10 +58766 16211 7 +40500 33048 8 +51871 15075 6 +18564 20078 2 +23186 16666 12 +9283 4319 8 +15072 4135 13 +26556 5657 8 +48682 37973 9 +52359 43785 10 +42470 13292 15 +25254 9275 17 +42613 34214 9 +32945 17780 12 +52373 17396 8 +23546 26930 5 +3160 11124 4 +26843 23753 0 +49241 12651 14 +36288 43557 4 +9301 14134 6 +24197 2677 18 +7297 46606 10 +1856 28809 8 +14867 33539 13 +11785 36225 14 +50884 37073 14 +46544 3618 12 +53460 55814 9 +54755 28647 0 +4509 24260 9 +41990 34140 7 +56073 11470 8 +37775 27923 13 +40055 14361 6 +36499 8385 9 +46216 43853 11 +25076 4265 6 +20062 49240 15 +18726 27792 5 +58819 42435 1 +34364 10776 5 +26965 13246 9 +19291 55221 16 +15921 34122 6 +44586 29683 13 +34995 56849 6 +13160 15634 7 +39573 38530 7 +53886 56734 8 +26494 33709 7 +10268 24338 4 +15111 34799 6 +25189 47498 9 +32196 53673 13 +28 13189 10 +43914 39733 15 +11321 1742 3 +48365 12591 5 +52680 5273 13 +29187 59407 4 +33439 9411 11 +23429 10551 12 +32770 30666 12 +5769 16047 9 +27386 40221 10 +22903 9236 8 +3050 51960 6 +5806 11298 11 +36157 29663 16 +47621 59158 4 +23568 58991 6 +53553 27556 12 +33871 38224 13 +40612 43175 5 +7027 43039 8 +21517 5727 13 +5381 32845 6 +59268 25426 11 +44181 52620 9 +41734 23462 10 +26920 13744 13 +21656 26423 15 +12247 38693 4 +48376 28658 9 +39147 10852 3 +9394 44811 9 +34772 46331 12 +6306 39830 10 +56089 35010 4 +3225 35833 11 +50551 11050 7 +34150 17962 15 +21417 13149 11 +23446 32333 9 +51235 12043 8 +38397 1255 10 +8488 43649 8 +30183 19765 4 +9322 54996 3 +11580 5958 12 +2298 41266 1 +53637 54754 4 +31655 47707 13 +11656 15497 8 +13282 7271 6 +46320 36704 10 +14755 50665 14 +39498 59287 9 +6023 25654 5 +21041 17837 10 +18712 1952 2 +42079 29307 13 +3571 13639 11 +32460 15804 12 +37242 15657 18 +15487 50387 14 +7659 43706 5 +59858 2583 10 +8150 23058 8 +26627 51180 11 +38118 58216 15 +20847 31117 5 +45020 38227 11 +6460 53007 15 +50613 57608 6 +35657 38343 5 +26475 1052 1 +21589 1195 8 +17735 45332 9 +7620 20608 9 +39066 47956 5 +26476 57863 4 +35545 13389 11 +19808 151 8 +51405 46650 13 +58723 36636 11 +38824 35835 3 +16250 35243 9 +23603 23082 9 +33536 45262 6 +6186 12883 2 +1080 34556 4 +59093 40265 10 +59711 39674 12 +57495 1318 9 +742 41721 6 +35219 41457 11 +17851 49796 3 +21190 33540 10 +50906 8286 10 +6758 11602 8 +50514 27805 8 +24913 855 4 +28225 30260 11 +24885 15665 8 +9161 11428 1 +77 3419 6 +35493 36028 9 +57681 30092 17 +24508 15124 18 +38816 30605 0 +39507 48485 5 +19229 55709 9 +37411 43221 5 +28241 54502 8 +32824 59764 9 +49564 30904 15 +15968 25856 7 +38402 841 10 +23616 15232 5 +9391 39627 6 +9027 3692 7 +42342 11873 5 +12450 12321 6 +33767 43059 5 +51739 49119 8 +58575 48705 5 +798 32076 15 +52176 43324 16 +37091 4357 14 +41236 37916 11 +38733 18024 11 +59761 19482 10 +3755 215 4 +49062 52222 9 +40504 8952 3 +50744 27604 3 +52953 18800 3 +46561 10453 7 +52862 33471 11 +10583 42412 3 +6360 53372 9 +59471 31626 9 +10831 7128 5 +57212 25698 17 +5613 54326 6 +45759 56839 12 +49517 22372 10 +4971 25499 7 +40596 54944 15 +22381 1394 8 +19041 35279 10 +4694 4522 7 +37818 23869 12 +30718 8045 15 +19781 14163 11 +15910 381 2 +9695 49735 2 +35085 15074 16 +31956 41637 3 +8520 22154 11 +25586 18498 10 +48552 8638 14 +22698 34861 13 +58232 20976 13 +31453 40963 9 +52376 59558 1 +58158 32520 8 +25171 48095 13 +39722 56715 5 +48950 50438 12 +24267 15122 8 +41600 31704 9 +51260 48959 7 +16928 3253 7 +10720 50609 12 +44360 12332 12 +36912 17848 12 +33255 34397 17 +58980 52377 8 +26870 53933 17 +58413 35189 18 +23218 52340 12 +54566 30894 6 +57208 3269 4 +8609 15126 7 +35338 38249 16 +2491 47916 13 +56780 23406 11 +42415 3509 8 +42914 8442 12 +28290 4680 11 +14506 9127 16 +30395 28000 10 +50645 24912 10 +21349 10318 7 +22733 14665 11 +54447 19910 13 +29171 35017 10 +2928 3374 14 +9821 4569 5 +25820 50150 4 +14346 40702 5 +48029 11345 7 +2260 5375 2 +27213 23517 7 +40379 23707 10 +53568 50401 8 +3436 18539 11 +50289 39559 14 +46068 41924 12 +54728 18752 3 +6 29617 5 +38623 17432 10 +40828 23482 9 +16563 48208 7 +35816 24392 6 +11724 57990 11 +51401 1956 3 +45734 4919 7 +4989 12578 10 +31116 21400 7 +5353 33654 1 +21409 27303 7 +43114 35284 15 +57647 58873 5 +47269 801 8 +53738 42502 5 +10701 32344 10 +6054 54001 10 +49588 57896 10 +27545 24060 10 +1169 10751 14 +48329 26449 11 +54892 10640 10 +22946 37035 6 +44610 56372 9 +33284 38799 15 +27155 18459 13 +40501 27515 15 +5115 51740 5 +45080 42519 10 +46743 11489 6 +9803 51870 3 +2384 8947 14 +54778 17112 12 +24939 6953 9 +318 49844 11 +58014 11709 4 +41098 28717 9 +12092 20236 9 +56789 29248 10 +7038 13020 6 +41392 2278 1 +35440 27095 12 +25073 25508 9 +14847 56285 9 +51988 24176 10 +26495 13096 10 +52369 40669 6 +34491 57791 15 +42634 11662 8 +29978 34968 17 +13677 18683 9 +58678 42040 4 +8091 15276 13 +28947 55226 12 +27123 57275 7 +39661 1692 5 +34283 23497 5 +50025 56005 3 +26588 56579 6 +52843 13296 10 +33143 6291 7 +42178 34421 3 +47313 2452 8 +20322 57261 1 +1943 42650 15 +3023 21305 5 +17565 20257 6 +44736 46476 10 +29656 13562 16 +43926 32668 16 +54487 264 12 +8208 31033 5 +59237 15315 11 +36571 7081 6 +53819 32588 5 +17844 24470 5 +32949 28812 9 +59680 11901 1 +59686 27172 4 +12594 51423 12 +38109 39708 5 +22782 7372 9 +45816 5450 5 +40463 40410 11 +56524 51570 9 +30523 10415 11 +1990 54762 8 +9168 26154 6 +7561 5191 3 +11324 53941 7 +26498 6045 6 +19738 1961 5 +34660 59515 7 +11911 25477 8 +41649 18739 4 +47810 9629 12 +18340 13506 7 +42118 22296 18 +21192 39488 11 +12741 44424 2 +3947 17111 14 +35576 33435 10 +27945 56888 14 +55039 13509 11 +39470 4187 4 +45187 48348 12 +42975 9914 6 +58160 7264 9 +24920 3707 12 +1180 52639 4 +16609 7653 9 +56463 58640 9 +59911 55379 6 +38152 23636 10 +54444 3922 8 +13376 25327 4 +11507 51540 6 +42477 29383 6 +57165 32589 12 +55976 50573 9 +37186 35650 8 +54344 30678 8 +54533 47436 7 +12167 48887 8 +29149 22399 13 +51329 10642 13 +20732 51183 16 +7407 51666 10 +4961 17584 10 +14782 26762 16 +56083 6401 7 +38653 56856 7 +34412 5670 9 +1601 6656 5 +52036 12904 8 +29386 29715 1 +30338 48680 11 +2076 32416 10 +12555 8603 4 +23641 9327 11 +5470 32557 0 +597 44620 10 +44902 30766 7 +51781 32613 8 +49016 42200 15 +18993 20744 7 +20659 29967 3 +25740 29929 7 +54718 47182 11 +45239 7956 11 +5775 7916 10 +53058 24322 2 +19389 6161 6 +13552 27037 11 +45603 16941 9 +24798 15397 5 +9624 39563 7 +27822 19039 7 +28191 180 3 +13709 22486 8 +51554 11604 2 +20378 25685 6 +25288 35367 5 +18941 30215 8 +19962 54620 3 +45197 20087 7 +53491 32537 7 +28704 42160 12 +48059 25868 7 +32970 31978 11 +4160 40393 6 +46882 45626 10 +54092 42669 8 +19154 21964 3 +36911 12385 5 +730 46926 7 +19893 49751 15 +6487 2352 7 +30165 14663 14 +13705 24243 11 +17193 25666 9 +22243 1333 18 +53388 54749 10 +22556 12726 9 +43573 30533 5 +8645 25459 10 +13690 24752 4 +7243 14468 2 +35943 13126 0 +5354 36698 9 +45233 22879 6 +9813 46281 10 +19947 56000 7 +54175 45544 4 +52349 57326 8 +59991 46682 8 +36170 46004 6 +44916 38746 5 +24616 58137 8 +56068 18403 14 +8628 33385 7 +19951 46850 9 +19692 39692 17 +6302 9309 8 +54998 7120 8 +35498 46899 6 +4180 24536 5 +34246 4690 9 +55563 9596 15 +49785 57705 5 +57151 37042 5 +30383 2020 14 +17926 51429 11 +32567 58383 12 +42530 50276 12 +43454 40421 5 +15560 8654 18 +58378 58337 9 +49772 251 7 +37215 12783 10 +44023 12615 4 +53534 8236 9 +41351 5168 7 +44647 27702 11 +51819 40891 14 +14025 27384 5 +4226 59837 15 +37000 51085 7 +41511 20430 7 +29567 31778 1 +39522 39967 10 +49871 36387 17 +50538 27610 5 +10876 53588 9 +14556 29430 8 +57507 18401 9 +28720 18875 10 +6454 43583 5 +7983 44064 9 +34373 18566 3 +49443 53147 1 +38117 14814 14 +7308 2780 13 +34787 52125 14 +8494 33047 5 +18656 58558 4 +52695 21063 9 +34037 20885 5 +50735 36748 10 +27006 40886 8 +35066 23874 8 +8730 16360 17 +44129 45245 17 +55075 9822 5 +5642 46915 4 +53638 31759 8 +51152 39981 9 +46538 27493 14 +49605 288 9 +58504 54497 11 +36016 57456 8 +33290 49448 8 +48663 9312 2 +14903 39318 9 +53080 16248 8 +58201 48465 11 +50050 13693 6 +42562 16686 3 +52128 56959 12 +1200 10818 9 +50012 57550 10 +39301 52771 6 +13061 1019 9 +48743 42580 16 +36565 31758 16 +59665 20132 8 +389 32985 11 +46495 47555 8 +10709 25103 7 +23538 38590 4 +12342 45990 12 +8107 50330 10 +31802 31807 4 +13158 17646 10 +38440 42791 3 +17514 58070 13 +26578 46241 4 +42220 17341 6 +57960 33752 2 +993 47748 9 +29286 18945 17 +51205 45141 13 +7719 11784 8 +44539 44455 9 +32922 3752 11 +37962 1204 14 +30536 51653 6 +32642 51242 11 +43090 28234 5 +33172 23489 6 +36119 28992 3 +12953 47397 7 +48662 56091 11 +44138 38448 9 +56975 51877 9 +41601 56841 14 +41341 37676 6 +39179 18651 11 +26515 37821 11 +14391 21437 14 +8292 33721 11 +54060 52380 9 +7326 36431 2 +14639 57195 8 +35974 6626 4 +19633 6086 8 +55115 38805 8 +45856 16960 7 +25370 35114 12 +36978 40914 5 +13262 38465 6 +24209 9966 1 +32050 57185 8 +39268 30454 7 +2827 12055 8 +39715 59151 3 +48232 49989 1 +10742 39735 5 +23774 22312 15 +44349 59993 8 +25386 27843 9 +3157 34975 13 +18585 49281 2 +54725 54169 10 +41321 35387 14 +31115 22560 10 +48648 31579 10 +7895 39689 7 +14586 50098 13 +38976 2497 2 +54554 8379 9 +28293 37299 10 +52495 44704 2 +22948 29038 14 +16303 35743 14 +56902 34904 1 +56097 46295 11 +22634 59239 3 +19668 11862 16 +36849 56793 4 +58425 12324 7 +36963 25846 13 +52284 53856 9 +27364 54560 7 +36204 39678 7 +41483 39725 14 +50502 17329 11 +26684 48189 8 +47529 21166 3 +58099 43848 15 +24398 51976 11 +16175 11975 10 +37765 39614 12 +42092 32514 2 +3765 3466 5 +41983 22642 10 +22567 15418 5 +7500 32728 9 +37480 44063 7 +48301 13426 10 +6907 28552 12 +52339 24828 7 +27392 30744 13 +37572 49563 11 +7618 22239 10 +15957 50498 7 +18895 25266 6 +6047 7789 7 +51967 49350 10 +45660 21526 8 +12530 49198 5 +49620 17681 16 +34277 52845 15 +23343 38768 15 +20215 5041 3 +33941 53607 6 +50411 31183 7 +44247 16031 2 +20509 44179 13 +51014 35563 11 +59335 40329 4 +1720 48254 10 +56642 14588 7 +43799 8705 6 +37674 14985 10 +44423 12049 10 +26507 32428 7 +50722 59069 6 +54113 9055 6 +22836 86 10 +5297 15345 3 +40332 56469 6 +54403 38795 15 +29528 7636 11 +47737 19870 10 +50432 4977 11 +31235 56466 13 +52790 27212 6 +36067 29635 8 +13640 18040 6 +44056 29602 11 +22167 21668 9 +27814 48621 7 +14445 59241 0 +25128 13857 9 +45904 28103 7 +57306 56291 4 +45144 58282 16 +57070 25422 14 +51493 58023 5 +43365 41195 10 +37805 22151 13 +51705 33945 8 +27328 28275 2 +49599 51547 11 +52612 3152 16 +30592 35699 2 +36262 21716 4 +34712 11066 5 +30278 38375 9 +54430 11415 12 +26543 50146 14 +4613 39038 11 +36136 43865 10 +2196 20463 6 +9877 52634 2 +8375 53115 15 +50215 53614 14 +11442 14610 15 +50385 33991 4 +36101 17540 7 +26315 9032 0 +32896 51888 8 +57046 52195 6 +43657 36779 13 +22171 38279 16 +40047 17402 10 +29001 56021 18 +22177 53064 10 +11802 55725 11 +8736 45061 9 +16408 46180 7 +29338 3796 16 +34768 23091 10 +13199 1224 13 +46203 5307 7 +3059 40352 8 +15997 18326 12 +26346 7709 9 +11684 54359 10 +5991 5928 7 +12581 14065 7 +28013 39842 11 +36578 33465 6 +36926 42319 9 +28205 8280 14 +14090 33199 14 +47127 36220 13 +54569 10605 11 +49866 18376 13 +51331 32213 4 +30977 59410 11 +27992 55172 8 +51295 53172 11 +24891 22378 9 +29922 36539 9 +14191 40415 15 +24524 2279 8 +54199 24796 5 +12661 14739 7 +55529 7100 8 +29594 33508 3 +18438 7411 5 +1551 40388 5 +19703 162 16 +9051 32316 18 +1700 35145 9 +58926 5299 9 +8380 36291 10 +28212 41475 7 +49535 24113 4 +41074 56827 6 +44284 13577 7 +44069 42070 11 +13696 7889 13 +26546 51300 11 +58414 26230 5 +21241 39904 9 +71 6585 10 +49302 59875 10 +47663 19927 12 +25079 37825 9 +50399 48810 11 +56165 59625 4 +5754 20701 13 +33760 46911 6 +48094 41636 11 +9052 12419 15 +20222 12891 8 +45838 7486 4 +19972 27039 16 +34222 53627 2 +55321 8487 12 +28388 6495 10 +57598 47827 9 +28784 12492 7 +27351 5624 6 +15020 14721 7 +39753 23368 17 +29516 28738 8 +43006 32227 4 +10276 33847 0 +21043 43184 9 +42141 7088 7 +59117 36800 11 +25187 36572 6 +21319 37699 5 +25568 38916 15 +19787 8829 6 +44036 27506 2 +54697 39199 12 +6152 34524 16 +7771 55767 4 +51652 30144 13 +23853 58653 14 +20385 25561 14 +12519 44765 9 +59547 4266 7 +9592 40120 5 +55043 46352 12 +13192 28598 16 +55310 25778 6 +24190 6485 15 +38829 28680 15 +3303 57012 15 +2178 28330 15 +22804 29965 17 +11936 49935 10 +26849 4884 4 +28692 9819 2 +14751 57751 15 +45452 16142 7 +22342 42657 8 +319 30008 16 +42483 32893 7 +48210 59960 5 +13835 35098 5 +9122 36858 11 +29887 23469 7 +4365 46464 8 +43636 8339 9 +35182 49040 14 +23430 4185 9 +18258 36766 7 +28483 54250 11 +19886 35620 2 +59311 13601 8 +11392 41719 8 +13776 42067 14 +34708 2267 9 +49261 32089 18 +45848 53752 12 +56261 9242 3 +25898 25748 8 +12401 29032 13 +10620 24122 3 +51599 34392 2 +17874 53412 9 +14830 1752 13 +24566 43771 16 +26976 50394 13 +34366 25250 11 +20415 44680 5 +5811 36540 11 +14862 3384 10 +17904 6997 8 +27022 38151 11 +13634 35134 6 +22314 36258 14 +31808 4792 3 +16496 14513 7 +37099 36647 4 +12189 36378 12 +5988 13799 2 +28153 13217 1 +48146 17371 10 +50839 49703 9 +47393 1892 8 +14292 56183 10 +28281 58582 9 +10550 43203 14 +17129 55515 7 +51131 11369 6 +8012 27682 9 +28603 47075 3 +44307 673 7 +17996 29474 6 +53243 4624 0 +42259 26452 14 +2691 31214 12 +58782 23712 3 +22438 49577 14 +21380 6336 4 +6399 26521 11 +5625 21601 9 +42223 25598 7 +7876 10697 7 +30845 26638 11 +17965 28070 7 +52706 59185 9 +59934 49538 1 +9190 16911 7 +23415 11927 12 +47334 2772 8 +34031 4878 12 +22315 35981 11 +39918 54575 11 +16210 3544 14 +44280 40685 12 +2768 1731 14 +16291 25528 12 +10172 42201 7 +14834 50757 5 +35664 46615 13 +55676 47595 11 +15534 36946 6 +56195 47113 8 +48393 54112 8 +26380 8425 12 +31776 55231 7 +14636 59568 11 +31859 7590 9 +45778 56598 6 +43509 21356 12 +43467 2082 4 +391 2378 10 +20983 53984 2 +28147 48406 16 +11635 4745 14 +43343 8467 18 +36838 7623 15 +55864 21834 10 +33719 49159 15 +31369 33340 5 +39902 51541 10 +41790 57286 13 +58304 55774 10 +40473 20714 9 +3123 26420 7 +5079 10360 8 +41568 11824 8 +30936 6902 14 +44738 55485 8 +58953 14770 8 +17323 33694 12 +45086 16816 18 +48167 27542 7 +26626 30145 3 +54991 43448 7 +59446 50647 6 +54705 29730 15 +19339 28408 1 +59809 47638 5 +19487 38203 9 +42113 54371 1 +28833 40166 12 +3472 3135 3 +31395 15544 6 +52765 46654 6 +30628 26513 10 +27723 36736 12 +36982 31102 6 +8259 33369 4 +32080 28963 9 +16501 23137 5 +1684 15956 17 +54890 25167 7 +34605 35686 7 +57781 44892 12 +44800 6939 4 +41176 17348 15 +2614 9456 6 +49774 49054 3 +51139 36480 11 +7139 35396 3 +32066 18427 16 +20166 56415 3 +35909 32816 11 +48336 6919 5 +47837 41631 7 +41459 38182 15 +16110 55849 10 +10226 13083 13 +7843 59569 7 +8848 21545 12 +17890 26278 14 +23459 49978 11 +32622 33937 9 +50677 4904 12 +23179 58620 9 +7674 48664 9 +18817 40157 8 +23609 47583 8 +54790 59736 8 +8732 48615 13 +40687 31312 17 +59746 35781 14 +33025 41169 3 +4788 54540 16 +40418 58905 8 +29879 17691 6 +22950 18931 15 +35408 33181 8 +47232 12497 7 +18600 16367 6 +19887 2573 15 +32193 11919 10 +1519 11029 8 +44626 42777 10 +41347 42083 11 +55847 56853 13 +26178 12152 3 +39569 28131 9 +42543 53295 9 +53074 36987 12 +24362 51745 13 +31556 57475 3 +51047 1015 4 +34383 51579 5 +50878 59295 16 +15238 17936 14 +47109 20255 11 +54337 24052 12 +22978 4769 9 +44479 59621 6 +10167 28456 0 +47300 13679 12 +47270 53936 2 +50770 37903 6 +7917 9772 7 +11800 29184 13 +8758 57883 13 +15483 36626 7 +3650 6505 8 +21859 10826 12 +44569 48162 9 +27915 54327 10 +20959 57003 2 +30375 54073 6 +55181 36451 5 +20797 40364 11 +4261 13105 11 +42971 46252 11 +11308 1087 6 +39966 48474 7 +46892 20783 2 +45823 24172 7 +39275 37057 14 +17299 13974 5 +29598 6009 5 +40913 56127 9 +33475 10557 11 +53087 16327 3 +860 20150 3 +37262 47019 5 +19552 52927 2 +33027 18054 6 +14710 352 15 +17916 11826 6 +37190 6289 3 +28568 44787 8 +20739 42660 7 +12985 19729 11 +47305 30311 9 +6616 35351 14 +2266 30293 5 +49891 8999 16 +2918 30062 4 +24487 3767 7 +37140 31820 11 +38757 29251 8 +43925 19904 13 +55753 7613 7 +41850 26821 5 +42549 51584 16 +17886 31985 13 +12928 26085 16 +57799 35469 9 +42709 25417 12 +32335 96 8 +31351 9476 9 +13768 26848 15 +33240 45345 12 +47713 34573 8 +38505 51825 14 +30711 56563 5 +26375 5226 12 +5767 26731 0 +40578 32863 4 +49215 25990 12 +24580 57903 2 +57879 22289 11 +35765 53006 11 +13759 42542 15 +49465 11068 17 +22118 7048 16 +42813 5173 11 +92 35273 13 +1042 8404 16 +11556 31582 6 +52418 20557 8 +53185 22283 9 +50449 55574 3 +19916 40216 13 +16660 48977 2 +33177 46790 8 +55376 22696 7 +49037 1610 10 +34774 33482 7 +33139 42600 9 +6498 21058 13 +28611 5782 8 +23320 48182 12 +56519 24874 10 +21342 28068 3 +15509 38092 10 +19727 47998 5 +14981 6684 4 +37128 12126 11 +31825 28424 12 +22907 35579 11 +20591 41838 4 +13732 16169 12 +29670 53698 12 +34976 53274 9 +39935 41137 0 +29723 10243 12 +55688 58586 4 +16238 3569 2 +3449 3927 15 +43023 13554 15 +33933 59272 0 +15175 51409 8 +59714 35003 6 +24408 6791 5 +59341 40873 16 +23369 59756 10 +29653 16898 9 +59951 7941 5 +32287 31971 6 +34041 47106 11 +46282 56769 16 +26900 14207 10 +58553 15626 8 +56774 42340 15 +17410 53018 10 +24905 29111 15 +50642 38526 3 +11241 10871 13 +45945 23696 7 +19850 46870 10 +37924 6025 12 +46493 27394 7 +42232 30211 7 +30843 10020 9 +40558 22754 15 +29743 30500 18 +29144 45089 10 +956 17238 9 +6061 5069 13 +58604 57709 9 +11360 16835 2 +49797 27224 10 +278 57795 5 +39899 10127 4 +48045 35301 5 +55723 31325 11 +36374 22655 11 +4775 32318 3 +40445 44074 11 +42556 52774 7 +35354 47945 5 +39730 287 9 +30396 35526 13 +23407 37119 10 +43155 37520 12 +25493 34353 16 +16244 29006 5 +36535 24535 2 +29917 22242 10 +38636 34788 5 +8330 49096 10 +59706 43760 4 +15157 1831 2 +57819 3424 7 +13364 58562 15 +24901 52400 6 +46694 8333 6 +646 10109 11 +51753 58536 6 +6911 4042 14 +55689 38123 7 +53417 2079 8 +13610 20596 7 +719 56115 11 +39327 14881 5 +16488 4211 16 +33651 5608 7 +55834 43394 11 +27055 14712 4 +46100 27390 15 +11525 23848 15 +24625 17618 2 +15268 6096 14 +57708 37666 10 +59242 37485 7 +27340 40010 11 +13415 6157 8 +49336 21394 1 +36554 56201 16 +21290 48125 13 +14076 6935 7 +34669 7909 16 +32366 26919 17 +51698 3017 4 +57811 14243 7 +2747 57804 4 +24157 46670 12 +6191 29579 9 +53393 6638 15 +55358 26152 2 +30831 46027 5 +27278 28105 8 +14085 33003 5 +18906 27406 8 +14061 26727 6 +52541 49158 8 +45634 23530 7 +33147 20230 13 +30736 38972 11 +4590 649 11 +919 55795 6 +59238 15643 16 +39851 40595 11 +18940 54415 5 +30381 39414 5 +33302 2705 3 +10716 27940 13 +59097 30886 12 +41620 37210 2 +723 17030 8 +31189 48953 11 +39130 33813 14 +18557 15184 11 +43176 29545 10 +19959 20935 10 +8523 59378 12 +33735 26730 15 +4572 11163 8 +57523 12549 5 +43204 10827 6 +11348 27200 6 +18490 44339 5 +4565 43823 8 +30045 13005 6 +50382 33963 7 +2591 30251 10 +23795 16574 6 +34601 37274 8 +46292 18522 3 +8357 8659 14 +37683 27259 9 +8225 31993 7 +7110 20481 9 +28422 40761 14 +24947 43780 14 +4299 28724 6 +37966 40865 9 +7967 57638 14 +53271 13619 13 +6232 15381 10 +56158 22825 3 +11754 57852 5 +17252 19125 12 +14189 59938 15 +28537 6972 2 +54308 8437 15 +30558 19095 13 +58863 17533 13 +57400 58935 2 +6055 16944 3 +29161 42506 10 +18623 21173 9 +3621 4312 14 +4106 20669 7 +6295 23315 9 +21264 12272 14 +5679 22478 4 +51655 7084 4 +2285 38687 11 +7087 9625 11 +14106 17562 14 +32955 38443 16 +57759 56635 9 +21531 39812 7 +13597 53820 12 +38812 15048 5 +9740 56017 14 +44491 18881 0 +36616 20199 11 +58029 53706 13 +37216 39182 9 +44913 10671 14 +1522 18862 12 +18953 30709 1 +42998 38335 8 +8224 29560 6 +48986 19089 7 +38137 35902 11 +14429 37521 7 +33390 24966 1 +27101 12777 14 +46235 34307 7 +2717 53476 5 +42907 22714 7 +39707 16608 2 +34967 34724 5 +29033 43789 3 +27085 27091 9 +33232 28486 9 +50993 41068 5 +55442 52252 8 +1854 36479 11 +44352 39374 9 +3610 3130 1 +46109 53809 14 +29108 45119 18 +37895 29544 7 +47622 34952 10 +1306 18335 15 +23011 11468 9 +58793 21746 7 +16747 52112 10 +558 50494 8 +39814 37045 4 +5923 361 6 +52840 47689 5 +45320 55561 7 +41199 7541 18 +38546 1882 14 +35508 26769 5 +682 14201 11 +33207 18884 14 +31028 45393 10 +35108 57473 2 +6890 222 8 +2287 49066 11 +14396 7101 16 +23090 139 13 +31630 44458 16 +53806 27290 8 +4372 12566 12 +55780 32398 12 +38271 29264 13 +55239 49377 12 +57369 51643 12 +18406 42720 8 +44965 280 16 +55266 7548 7 +55024 3519 13 +23984 42049 6 +44648 11511 4 +35420 24733 8 +49070 53720 4 +32312 40568 7 +56731 2220 12 +670 11266 10 +16013 46092 5 +59100 46297 10 +58719 51473 6 +31720 5762 5 +42628 34847 9 +33100 42378 13 +22350 47603 9 +1853 12276 8 +55483 34622 9 +40977 27226 18 +40801 23657 3 +27191 13229 14 +20639 7010 15 +53932 28669 4 +13609 16891 6 +8633 49766 9 +39032 25137 2 +6605 13181 5 +30635 37179 9 +7957 8373 7 +54339 26984 4 +46497 12461 11 +20221 29013 9 +44311 33370 8 +44152 34552 8 +8626 7298 15 +35861 38825 8 +48557 9505 3 +36815 44251 7 +53921 10122 4 +42707 5283 10 +25023 25756 12 +41500 25854 8 +27453 26217 11 +15203 10718 9 +53612 23593 13 +12682 32551 9 +46444 45480 12 +33782 42176 7 +57123 11401 10 +3320 12501 5 +56173 28785 12 +36993 59475 11 +22631 18456 8 +41663 51585 8 +9832 23120 8 +44459 50741 10 +5220 19343 10 +4605 19901 7 +52256 5529 9 +36146 2644 6 +13298 22852 5 +22173 25615 8 +11524 39311 8 +9894 48350 2 +45550 49043 10 +33421 21871 10 +44797 18263 2 +28713 16720 10 +7535 28104 11 +11418 47983 6 +419 21240 16 +19542 21189 8 +310 20920 10 +27075 6835 10 +13273 10539 10 +3999 31224 10 +50415 49557 7 +41533 40351 11 +27855 34074 2 +44335 11386 6 +2839 44495 2 +8176 38417 3 +51007 51971 15 +13821 7979 13 +27261 3372 10 +21347 6850 15 +49298 58790 14 +4079 7103 11 +10682 33600 8 +5407 33337 15 +31743 28921 11 +34414 7904 17 +25382 34384 7 +19725 53474 11 +41006 54002 9 +37230 47346 6 +18016 41534 1 +14740 48720 5 +1276 52623 9 +57407 44778 9 +52164 31814 7 +5194 47281 5 +31436 55552 8 +26641 59523 7 +27401 54006 8 +37616 25349 6 +54352 2581 8 +31797 28235 7 +45873 18793 16 +2505 41043 5 +59362 53288 13 +22800 40155 4 +351 24717 1 +10132 41915 13 +32120 30116 15 +27899 30682 7 +32545 33928 7 +51937 27135 5 +44084 47496 12 +54473 19250 7 +22471 45737 17 +37769 11283 11 +24651 59582 7 +42926 8655 9 +24490 23064 13 +37459 57292 15 +2065 34739 11 +6322 4740 11 +12906 7940 11 +14315 11302 14 +55813 48941 15 +28467 28400 12 +9566 25621 8 +54556 23359 6 +8859 40071 9 +35751 6313 14 +54969 23786 6 +47893 31719 10 +6538 33677 0 +56318 1223 8 +29926 13163 4 +20115 35136 13 +8687 24452 3 +46636 8281 11 +39587 43290 10 +30672 23128 16 +40515 273 11 +24291 35571 9 +50073 59533 13 +49739 32386 5 +24860 9881 9 +13418 10193 13 +20996 25958 12 +28329 2385 18 +31132 33261 11 +20160 24896 2 +34632 25051 1 +53763 9538 14 +147 29869 6 +58182 32468 10 +620 44764 8 +16040 11036 8 +25210 15478 9 +13456 5152 12 +14741 28797 13 +46242 7922 12 +28094 12850 8 +19617 53254 10 +17636 40817 6 +27696 56095 9 +45545 59395 11 +23797 29954 9 +16456 20361 3 +20077 9240 3 +19932 18507 8 +44484 14218 13 +46558 40799 15 +16809 47279 8 +144 7900 13 +41272 30895 9 +37852 48379 9 +4001 20554 12 +29876 30964 10 +54603 21653 7 +21969 42448 9 +13957 3208 5 +43471 50337 10 +2235 37611 13 +46581 17522 11 +28778 27701 6 +46189 31642 7 +53141 9175 5 +27097 56915 11 +43691 49334 10 +10439 15917 2 +27678 17841 10 +32860 26408 9 +25793 56871 8 +1571 7160 1 +11860 45350 2 +24955 6432 13 +29078 50918 10 +55434 27926 14 +42674 3777 0 +7577 41522 11 +42557 32067 18 +49360 31819 10 +45872 50646 6 +37626 26933 10 +22616 8057 12 +58196 59071 2 +51113 17772 14 +46051 32307 10 +31947 56946 6 +18315 48150 15 +37535 48789 15 +54805 42573 9 +6715 33005 8 +48173 40968 2 +14401 27736 5 +10113 54191 5 +23507 33491 10 +4220 57787 5 +37639 24591 8 +2165 31446 8 +43808 54392 1 +23194 22208 2 +9462 13884 6 +22835 53394 4 +22134 19968 8 +42162 41489 8 +47579 46845 6 +5569 9954 14 +1950 25000 12 +20180 2718 4 +53219 56828 7 +8391 41044 15 +54121 9145 4 +37447 13059 6 +31405 37864 14 +37297 26802 8 +48879 16336 9 +37296 17473 3 +43561 6440 3 +55857 21399 10 +15582 31619 6 +57004 17474 7 +21123 31718 8 +16739 38884 8 +38295 461 9 +25619 48337 3 +3202 23842 9 +21160 21147 9 +5904 37058 6 +2704 13627 9 +51109 11782 11 +18370 40191 8 +12768 27628 9 +39791 14001 5 +42964 51110 6 +18025 37175 13 +52417 55417 5 +17450 43542 11 +41036 29757 7 +32586 11896 5 +40029 49837 8 +18502 22091 13 +37538 15565 15 +14911 45924 12 +33510 2236 7 +15668 46916 5 +44054 29352 5 +18669 25048 13 +6826 11366 12 +5865 42248 12 +15756 30072 9 +23627 53300 4 +32415 7643 12 +31684 28230 7 +10944 27655 15 +17737 18105 15 +54173 42576 9 +6066 36384 12 +36169 58842 9 +50817 38695 12 +46879 42911 8 +51826 27444 2 +51127 17748 1 +5350 14397 13 +9826 52544 8 +47914 31492 2 +45482 46863 7 +2799 12542 4 +19018 39006 3 +41981 3825 12 +52886 45469 14 +32232 638 5 +26567 15755 13 +28157 36910 9 +858 45841 17 +1367 22926 1 +43869 56076 10 +2541 33716 5 +833 48010 8 +32671 9079 13 +11175 58806 10 +38779 43872 2 +23633 56638 12 +11394 47025 8 +31335 39567 11 +13275 15684 3 +40588 3727 11 +38380 26431 2 +38880 53794 14 +4415 23211 5 +36287 44029 3 +17755 4975 9 +27362 1781 9 +20142 42140 9 +586 269 8 +51283 51778 11 +41614 23582 8 +38603 13708 9 +52512 4110 8 +45163 35437 11 +9674 56316 5 +29973 25055 12 +42207 34265 13 +31389 247 9 +3444 36265 3 +43537 23088 3 +37342 57966 10 +50809 49720 3 +45435 14096 12 +59684 1668 5 +36964 23890 15 +37645 18543 4 +4283 44986 5 +52662 52345 10 +11405 34509 6 +10631 13065 12 +44543 37185 11 +26866 36021 6 +37076 27314 9 +22928 42099 5 +28002 42539 2 +59731 17378 6 +23723 49945 18 +10543 17209 6 +19882 11261 10 +3246 5563 7 +40233 34375 16 +29795 46210 7 +38839 246 2 +26240 45430 7 +43329 23976 17 +26286 16195 9 +10619 31586 14 +18152 6141 14 +13050 41961 10 +17714 48560 15 +32624 36791 10 +38769 24461 2 +30258 46710 5 +46737 26398 12 +29299 58597 9 +52122 1954 7 +27788 34596 4 +44578 1268 0 +12021 37686 5 +49851 45193 8 +35681 52075 1 +9823 19844 7 +20869 59136 8 +41223 47219 11 +41657 57534 12 +45352 45392 16 +40225 38766 4 +46794 53900 14 +39065 13885 13 +51772 38684 2 +13206 37641 9 +55090 17069 14 +30053 11935 6 +11570 3899 10 +51733 548 2 +44981 54043 8 +44948 641 18 +35262 31756 5 +38173 6114 6 +53923 17819 8 +20135 12127 10 +33902 23665 2 +28350 2807 2 +13961 31627 4 +10212 489 4 +1607 58985 2 +7225 22210 9 +14865 4232 10 +14392 53084 5 +21729 24384 11 +4927 1702 13 +59852 31643 11 +13778 53740 6 +55040 29405 2 +30598 26972 14 +18144 23738 15 +12358 18530 11 +6724 35639 4 +29098 34625 2 +827 12069 18 +562 16632 13 +13688 44407 13 +7207 5513 6 +13804 4214 8 +17173 1487 6 +45467 25818 0 +4047 30068 1 +45533 13121 9 +42392 57293 10 +17357 11184 8 +20738 43756 7 +17783 56647 14 +28557 10440 7 +38449 14766 9 +20224 35001 3 +38933 25433 6 +11783 18349 10 +28057 51276 11 +27735 32472 1 +14916 27382 9 +28142 56048 7 +32884 63 8 +19535 16590 6 +41537 48421 3 +49532 36544 13 +7660 43580 11 +32064 4671 18 +35175 31649 5 +12571 3598 16 +54909 58330 13 +13815 1978 12 +38355 6658 3 +1578 22915 9 +5032 57989 10 +28957 11559 3 +37744 29980 9 +38762 32595 7 +39506 51013 14 +36880 9675 9 +1058 25259 7 +52872 37220 1 +45242 30632 15 +59228 31942 12 +10299 5559 15 +3893 52555 12 +49795 47780 4 +35534 58041 10 +2333 13437 9 +53230 36900 11 +48214 36831 6 +23704 57389 11 +16301 41621 16 +52933 47633 15 +11745 4503 18 +57105 46718 3 +50763 41602 12 +56711 40537 6 +41055 57947 6 +27829 31835 7 +11537 32886 2 +55946 16811 11 +57512 58614 14 +39691 53846 5 +11606 53906 9 +33610 22546 16 +46370 10307 9 +27100 59534 9 +30139 24464 13 +5336 5834 2 +46162 54806 4 +25704 58123 2 +16190 56345 9 +21073 43200 5 +50304 8846 15 +26829 54597 7 +53899 45042 1 +11953 2008 5 +47509 14116 15 +42253 3146 15 +55275 35652 2 +34387 5693 9 +25790 31520 9 +13156 1078 2 +22858 52966 10 +13516 5859 4 +12509 36235 10 +4582 10820 17 +52736 5877 13 +33347 39574 9 +57773 25236 16 +31943 58279 4 +32843 6346 5 +35300 54331 13 +22726 36837 6 +28541 4602 8 +1787 8946 4 +50595 6349 8 +2543 43291 11 +27868 42328 9 +53047 56667 14 +23208 5527 5 +56295 38742 16 +11166 3012 7 +50943 41051 7 +22114 53929 9 +48438 2642 0 +49962 14138 9 +25441 5825 8 +36350 6834 5 +46593 36951 9 +36664 57169 5 +44120 24978 1 +34618 43877 9 +53994 30291 2 +34275 55415 5 +57099 48500 10 +8315 54184 14 +56993 35653 4 +52629 56202 5 +32634 36874 2 +19204 38473 8 +56228 7574 4 +2759 46408 9 +44400 19106 14 +11972 23960 7 +22731 50889 6 +49752 31268 15 +24428 39386 10 +4107 39282 6 +52254 44121 1 +48574 1973 4 +59864 36656 9 +53036 14070 9 +34737 10675 1 +7412 40289 5 +52305 36808 9 +34567 41610 13 +43826 52768 8 +51000 46039 7 +29648 30312 11 +27522 3016 7 +15318 32997 4 +8810 53105 4 +34512 52936 4 +27862 58053 7 +56479 5131 5 +15407 24427 2 +3069 42348 10 +40867 6796 10 +29625 48917 10 +25971 11490 10 +40005 39895 12 +53782 25387 16 +30303 55112 7 +44566 4017 12 +3294 17771 7 +53825 39054 2 +12606 50229 8 +37804 59444 8 +10341 14168 14 +7867 36278 12 +25744 58893 9 +11830 6006 17 +54032 36411 13 +27579 6986 15 +8187 45438 1 +19670 57616 13 +40197 14877 9 +21387 53503 7 +26044 421 6 +28374 18516 4 +34416 8842 4 +38234 14080 8 +47912 19276 8 +10054 57924 8 +9502 55203 9 +34906 53042 6 +51050 54952 8 +23527 30285 8 +30731 16995 5 +45501 44444 8 +117 39261 9 +48262 41667 6 +52749 50998 10 +25671 30329 5 +49048 24889 13 +4490 3638 8 +20119 39265 7 +34600 53024 12 +30478 10374 17 +31402 13845 11 +49098 487 11 +42005 25335 5 +38628 57221 5 +23773 39128 4 +34360 27991 12 +52906 2532 1 +35538 17711 2 +46195 26875 7 +3035 37106 8 +19543 38499 1 +19805 42258 15 +23132 19591 9 +20521 7267 8 +25206 31540 8 +35854 40915 9 +45128 42138 2 +50238 42807 11 +38391 24861 8 +10309 11086 9 +43372 20479 13 +5873 19760 5 +46430 55316 2 +18191 58124 13 +37869 22451 4 +31239 10533 14 +7935 26147 11 +50170 15091 16 +42486 45406 3 +23074 52923 16 +22863 48322 3 +19752 21761 12 +24268 21960 0 +15844 59152 11 +27047 56810 4 +1077 10206 6 +9199 55452 8 +8531 39490 7 +47120 32145 16 +23778 37894 8 +33625 48812 14 +41078 44323 15 +57315 33225 11 +1251 34779 15 +33691 53026 4 +3989 28608 7 +8121 34209 14 +49409 36631 4 +35150 53173 7 +53624 30193 10 +9507 13540 8 +30277 3552 12 +19516 15475 3 +3881 6803 8 +25377 58692 12 +12796 51618 0 +127 37269 4 +35427 35385 7 +48970 41050 10 +58823 172 13 +18323 37890 5 +1672 14598 11 +22164 36241 1 +44149 23599 6 +6479 51308 9 +46847 57373 8 +27504 13036 11 +49380 28247 9 +54599 54015 14 +59643 24974 4 +16243 37320 5 +18807 7714 13 +9119 23438 14 +29972 9396 5 +41370 24773 10 +52770 58508 17 +1175 3932 8 +69 55104 3 +52439 17761 5 +1024 22513 12 +21586 38280 5 +25543 27671 10 +24136 32303 6 +32478 9390 17 +53965 45481 12 +15777 30773 4 +19806 508 10 +14323 22207 1 +47366 54441 12 +6483 53310 5 +48767 5836 11 +28210 44601 9 +29444 53076 6 +34347 4517 15 +47463 43683 10 +41142 4743 13 +23963 9774 13 +21979 8746 9 +56123 21464 8 +23316 38772 11 +9741 33710 11 +22531 43233 9 +22346 41186 12 +37183 12475 9 +12536 37011 4 +58256 25692 8 +13645 19277 8 +29889 20617 7 +13230 37154 1 +29024 16273 10 +25844 21310 12 +28970 33293 1 +51545 50353 9 +24652 4646 9 +53365 49422 11 +52187 45369 10 +48738 1405 3 +27389 20486 9 +36107 58037 4 +30005 11001 13 +18195 39693 16 +20969 56357 15 +43330 44538 10 +19485 5503 9 +15288 2701 7 +33330 56398 3 +14251 49646 9 +38254 11210 13 +24234 16736 14 +52919 8709 7 +44268 19301 5 +6868 22600 11 +21003 53153 12 +25618 5222 8 +45969 16437 16 +49706 25300 8 +54203 8182 12 +35795 58523 6 +34570 23736 9 +50578 10897 10 +11482 33336 17 +28314 51044 7 +767 27821 4 +13636 13378 9 +44460 35777 7 +50911 32169 3 +8965 47791 7 +45928 38070 6 +43624 4149 1 +3843 19255 16 +53589 3726 13 +16109 19478 6 +24099 52916 4 +58685 53309 6 +50505 42247 14 +44249 30274 4 +34251 17232 1 +14590 32164 11 +36869 46087 9 +37810 31376 17 +33500 43076 6 +46151 37494 14 +51080 24079 13 +11281 40987 1 +46170 49638 9 +41490 28585 6 +28671 28396 9 +44501 50486 9 +30155 58001 10 +14176 34770 12 +58987 55727 4 +58208 17107 13 +57927 11940 15 +9898 50836 11 +3032 41832 10 +7785 31491 12 +12507 39029 5 +52105 13395 9 +4575 7324 8 +15240 37860 4 +58961 28190 13 +58650 53406 10 +5365 15047 12 +16737 14464 6 +7850 43510 6 +53428 15501 13 +26326 27659 2 +32791 37524 9 +37361 5565 10 +12431 59726 14 +27157 29396 8 +54545 17899 11 +52628 491 1 +40493 26909 7 +3673 50952 1 +16296 56270 12 +25188 3891 12 +51043 36063 13 +5990 51640 9 +1021 18266 4 +15640 46518 9 +44967 42237 6 +8539 30252 10 +44067 38429 7 +44331 36137 14 +52405 51557 14 +31205 57860 14 +59123 45270 16 +23602 8140 14 +6717 24518 16 +43186 7358 0 +31229 39820 6 +54555 20791 12 +53440 59733 15 +51532 3061 11 +53339 2855 2 +21136 9488 4 +54782 52987 5 +45136 14530 2 +29554 23505 7 +27995 34659 11 +28379 9350 8 +5604 50014 4 +40188 15510 2 +51074 28817 13 +49676 17384 13 +6766 50423 3 +11871 52587 13 +30577 53595 9 +13017 14333 11 +12016 27544 5 +46075 14922 12 +25134 39831 14 +43091 38890 15 +2761 36726 12 +48187 3605 1 +17264 3454 11 +4379 47057 12 +40576 27496 10 +53827 50963 13 +52435 54063 8 +41332 41845 5 +24449 31725 9 +55886 36628 5 +45289 32264 5 +57237 33686 10 +12265 24981 11 +43684 13142 4 +6576 42712 11 +40458 18306 13 +18270 1067 9 +55250 13169 15 +2632 38072 7 +46800 47230 11 +10833 54919 14 +3442 7393 8 +4827 30050 14 +52215 50038 13 +49020 44109 4 +23255 17824 10 +13478 16782 9 +12734 16905 1 +58891 31114 5 +40919 4945 11 +38251 12706 9 +36598 58832 11 +3118 18675 8 +41110 46028 5 +16607 33587 3 +22761 22113 3 +17334 45235 0 +20148 4898 9 +48503 37932 17 +25083 26949 18 +33934 10215 13 +44049 49899 3 +23944 228 12 +15700 57088 5 +35783 36792 14 +44345 27812 10 +16673 43393 12 +15606 12856 8 +21403 37739 0 +44643 3960 13 +41039 55013 15 +44625 44656 5 +12259 34776 6 +23168 11750 14 +43453 3836 11 +37621 39633 15 +36437 37273 9 +53077 11214 1 +17679 36366 13 +21540 25632 11 +53286 27950 15 +49329 15030 5 +59968 17911 8 +31078 55109 9 +55618 25984 16 +55248 37728 6 +39281 16695 7 +16566 3697 8 +22423 14551 11 +58242 41935 17 +15228 18976 11 +43619 9689 5 +58911 28949 11 +36908 29522 2 +4248 25065 1 +5008 53331 15 +32349 13684 15 +47321 45610 5 +28799 54064 13 +40898 46452 4 +6910 36434 6 +19234 55214 4 +49219 57607 10 +21593 9452 8 +31419 3474 10 +24214 22327 10 +50314 30012 9 +9725 46933 3 +1682 57526 7 +3339 12862 7 +4700 24179 14 +12219 59676 5 +21406 19950 11 +24775 13906 12 +53354 22221 6 +56260 58538 5 +2212 40766 10 +43380 3106 3 +2758 8956 9 +984 54132 8 +20231 59171 7 +48057 43173 13 +21346 2596 9 +45699 34204 6 +31882 33781 8 +50296 47064 11 +21965 19397 10 +50930 35903 5 +55492 56924 14 +40636 20577 3 +29994 52589 4 +36002 58068 8 +27675 46031 10 +38352 7858 6 +36805 47794 8 +24900 36320 9 +10428 39371 16 +34030 39833 12 +36889 26622 13 +19538 52973 12 +38221 59524 9 +24032 14518 4 +12772 8834 9 +47547 43311 15 +35878 11503 11 +27533 7963 14 +26455 54920 15 +22791 27699 12 +53735 18883 18 +49928 11610 11 +12529 49444 16 +21142 5548 8 +38688 22854 16 +50601 24600 13 +33117 9613 13 +22292 21188 16 +33544 53298 9 +56626 42400 9 +56936 50602 11 +22718 2168 13 +47165 7395 11 +16971 12674 10 +57217 44047 9 +43024 14879 8 +4812 9386 7 +19224 35144 12 +10811 19872 5 +21868 34850 10 +10230 11019 0 +15364 53201 13 +55118 57611 16 +14169 31656 9 +50518 31631 3 +1388 14932 10 +1243 59557 1 +55964 19507 5 +52278 28021 3 +48919 32016 13 +35892 52920 13 +36222 58539 13 +14632 13173 15 +21759 4142 0 +46221 13278 12 +15379 9192 6 +8607 35767 16 +41423 49258 12 +57559 39200 10 +42016 15298 11 +21837 51794 9 +21245 4073 12 +39620 16945 3 +5160 12216 9 +19166 52848 8 +17659 21228 10 +37475 41026 13 +13534 30883 10 +58760 26618 7 +44344 37632 2 +9606 55414 12 +45789 17535 3 +681 36652 14 +22857 4947 8 +48757 43763 9 +58520 53196 16 +13566 57198 13 +9577 48084 10 +33541 44886 3 +47027 58035 3 +57696 52002 9 +376 44136 6 +3832 23207 12 +5540 559 15 +35613 54644 10 +32689 25190 8 +6978 25331 8 +44949 43726 13 +21642 18577 12 +42567 43058 13 +8199 4288 9 +5018 1725 6 +32849 52870 12 +17235 56771 17 +37309 37613 5 +37730 4235 6 +36855 21469 3 +59005 38852 9 +2443 59653 4 +41944 1244 4 +47782 23607 9 +29322 44237 15 +28197 12412 10 +37166 33909 8 +36069 19544 8 +15160 4091 9 +29327 12647 7 +27252 50604 10 +44239 20497 9 +34984 48974 8 +32026 25949 8 +15602 15675 9 +10258 28359 8 +48484 30128 15 +47049 22648 16 +38120 5888 2 +41183 39629 13 +5728 36386 11 +19645 42215 3 +59255 10630 12 +31589 45953 7 +22751 12304 9 +58142 41400 11 +3492 5383 5 +1992 30117 5 +46000 1532 9 +15256 55130 7 +40975 57253 8 +28910 57574 2 +7409 53466 5 +28869 20863 7 +114 33001 5 +31108 40508 12 +49569 46040 2 +38163 47221 8 +39503 20542 2 +15269 8925 10 +50414 2779 18 +54275 2891 13 +42511 48138 13 +54205 12829 11 +37898 58920 16 +10681 56713 18 +34833 17986 3 +58841 52302 9 +37681 42490 15 +13758 29448 7 +50849 46096 13 +3382 29064 11 +38167 54479 4 +14098 54887 8 +30597 6390 14 +26162 8833 9 +51796 22608 16 +20894 12858 6 +12477 5518 9 +29908 33016 9 +38490 14249 10 +32317 16884 11 +54039 48113 14 +6659 15356 9 +43944 44521 12 +10546 44695 13 +42741 36890 8 +44823 2409 4 +870 22798 2 +37307 30283 6 +8905 53603 8 +16344 40322 3 +57592 6391 4 +10060 29204 9 +17520 33613 3 +47821 5628 11 +33423 11538 16 +43299 7229 15 +13680 29737 17 +32974 53118 1 +16798 11337 9 +53444 1049 0 +6780 26051 9 +12577 1452 5 +699 18198 7 +14803 59293 10 +4643 36608 8 +16033 49611 7 +22048 41813 9 +57231 57342 7 +56812 11573 12 +35946 17791 8 +39760 28435 13 +4549 32494 4 +15905 54259 3 +50462 54800 9 +4860 22813 16 +13515 6927 13 +26396 46392 12 +56795 26465 6 +7892 20349 0 +13824 11061 4 +56098 1819 6 +22610 34334 10 +52772 49108 12 +8686 19528 9 +49714 35871 16 +52972 24897 5 +58166 46081 13 +26905 28418 4 +21748 41424 10 +12712 2551 13 +24237 56468 11 +58008 8679 2 +33784 56124 9 +24658 35827 10 +12425 5752 14 +26107 17600 8 +46646 52757 8 +57159 56900 16 +54409 59577 8 +54759 59428 8 +56300 5118 13 +14356 21800 0 +22343 26441 8 +29237 31414 11 +1939 1105 17 +58964 10861 2 +29966 6922 15 +46683 12648 8 +48290 26775 9 +18071 25961 5 +41634 37044 6 +30927 11121 12 +22337 17136 7 +51844 27687 13 +48509 1623 17 +30824 51145 12 +31507 36489 16 +24202 47076 13 +46883 35263 12 +58696 1326 16 +32677 34804 9 +10053 19386 9 +11362 27651 4 +19136 1796 1 +49749 45065 12 +4567 49242 11 +53734 45513 0 +11122 26351 15 +52763 56641 15 +1208 33076 13 +26777 6011 11 +37239 4550 6 +825 3440 1 +52532 45054 11 +31472 43971 6 +45389 45307 3 +23977 36202 7 +15115 57788 11 +56063 53987 8 +46441 29658 7 +8878 35531 5 +337 27072 15 +48989 57935 7 +48533 2341 9 +58185 2732 11 +11057 38668 5 +51509 15248 9 +14840 40111 8 +6908 32163 16 +11412 24445 1 +12063 31434 8 +4168 42754 7 +105 43851 3 +14599 27560 8 +50520 57603 8 +27846 12840 18 +51908 42574 5 +57519 22570 13 +11320 50317 3 +26856 36167 7 +54931 58797 5 +21789 35960 7 +8253 47745 9 +38187 30362 9 +50393 14989 14 +48916 194 5 +27283 37990 6 +38470 38792 14 +46511 34285 12 +18488 4501 9 +25567 53613 4 +6084 52955 9 +13135 33075 2 +22886 54831 2 +21454 31307 1 +31093 19802 3 +12613 35994 6 +43819 43854 6 +17389 39448 12 +24936 12916 11 +5134 4821 5 +55601 2952 1 +33130 45205 10 +33158 37914 2 +35780 22124 6 +535 26111 5 +35804 38447 16 +9393 44420 7 +45793 47016 14 +39209 21784 6 +43957 14722 5 +40658 49630 9 +17640 10996 10 +52563 25655 12 +56044 3184 10 +1119 16560 9 +55693 14853 8 +34631 5249 4 +21042 5485 8 +16645 30064 5 +7030 21153 6 +18084 490 5 +46818 12058 4 +17350 9798 13 +25443 56494 10 +29190 1593 8 +7907 10527 8 +23030 35102 8 +58587 35701 5 +43190 15819 12 +29588 18529 13 +57161 58175 5 +38796 5473 13 +44145 9436 11 +23898 48285 14 +59783 41221 8 +24714 34083 2 +44222 40845 7 +11719 48831 4 +52638 1305 18 +16570 31153 12 +26621 23212 14 +45901 30823 15 +18809 27880 9 +14544 37344 13 +39643 24553 16 +3516 13041 9 +18137 12375 1 +13850 59945 9 +11963 6757 5 +33479 56161 7 +14357 21637 5 +4784 24801 14 +36859 39222 10 +4086 2878 3 +43924 24217 12 +19063 21109 4 +977 31896 15 +56200 10547 12 +48906 33999 17 +17778 35187 8 +42805 49768 3 +29255 52699 14 +57663 54935 15 +3602 11048 7 +13881 52716 6 +46901 16908 10 +1704 55099 9 +38307 42952 6 +25077 3924 8 +21585 23060 6 +52409 5925 5 +36999 29368 5 +6150 10626 10 +23560 26445 9 +46266 47953 2 +17168 25222 9 +35869 2789 9 +33824 11952 10 +24372 33378 7 +41819 1877 0 +22069 31932 4 +4649 13972 4 +6238 32684 14 +9194 13781 8 +58999 7871 12 +4804 19847 2 +29031 4018 15 +3640 10982 8 +18826 5860 12 +26258 28122 0 +47204 3645 14 +28631 39949 9 +50946 46458 8 +30109 30924 14 +29517 27715 5 +33808 42654 7 +45655 27534 6 +59254 53787 8 +17092 3369 9 +49211 21489 9 +41363 40547 16 +34052 29358 13 +3520 41253 14 +40313 36916 7 +13279 52288 5 +50140 19570 11 +3052 35229 8 +54960 495 7 +55170 19829 5 +28110 31635 3 +31525 10449 17 +38973 18907 10 +17922 13150 11 +15193 43154 11 +30658 3916 11 +31366 15673 7 +34314 20028 9 +59449 33348 16 +4218 10476 2 +36294 38793 8 +39085 16020 14 +46935 37238 8 +41405 13687 16 +30471 38048 10 +29106 22275 7 +33880 32419 7 +23204 57279 5 +55998 55792 12 +36720 24241 17 +21371 3803 8 +31344 43051 13 +19143 49063 16 +33499 14101 13 +1903 41063 14 +42623 33516 1 +13785 43881 5 +42586 7183 1 +21447 43470 10 +27858 12147 12 +28581 34004 9 +26284 5291 10 +2822 54629 6 +9781 50803 7 +42691 9824 13 +25050 52227 7 +52621 26442 7 +18900 3889 3 +46905 19065 8 +10032 46917 6 +5458 12336 4 +52842 43463 7 +25046 42431 14 +50259 35359 3 +59098 25333 10 +20668 41316 11 +41310 4701 9 +24883 10273 9 +25476 49744 10 +41451 47552 2 +18768 52944 9 +24015 3396 2 +46762 56676 13 +44504 52067 11 +35693 54590 17 +42878 21119 12 +23331 21844 6 +2612 11081 9 +39835 59929 7 +32354 13078 10 +23922 9857 6 +18283 46745 8 +40256 37942 5 +10980 1264 8 +36405 36619 9 +57847 17515 8 +35532 33644 11 +2353 57491 0 +40550 4310 3 +29102 29619 2 +15664 39496 14 +17468 57227 8 +36004 6229 10 +8874 42459 13 +55656 16127 4 +48933 56804 7 +58105 59548 10 +17021 37857 16 +43003 35574 4 +28278 11718 4 +13347 30301 1 +41705 14628 13 +23745 15178 14 +40749 32099 9 +10708 19016 10 +49810 34064 3 +35754 59992 16 +8647 56125 9 +27510 22820 11 +28213 7738 14 +35977 50700 7 +4563 14659 5 +19440 50160 7 +39375 37604 7 +59789 44211 7 +4713 49168 2 +31111 29009 13 +31486 3218 12 +24074 49439 14 +46590 15593 15 +10633 33186 7 +36601 30600 8 +1654 44699 9 +51619 32578 10 +39518 7811 11 +14583 57081 11 +17670 3065 13 +9180 47870 12 +27210 37327 15 +5671 51041 6 +26720 10006 9 +38630 28384 9 +40345 1460 6 +6111 53961 15 +7301 35953 12 +17055 56012 11 +16838 49166 4 +8438 26030 9 +969 59909 15 +47915 46407 6 +57 37878 16 +55478 1576 5 +30633 55692 11 +56271 2172 14 +54834 9766 5 +52720 26144 1 +45277 56556 1 +8036 1737 12 +40955 50255 11 +57876 45353 6 +30378 39320 15 +25758 48001 8 +41167 41156 6 +54791 52632 12 +58063 25973 7 +41708 16260 5 +23978 41311 16 +12297 33189 12 +32214 39766 11 +1372 13303 6 +54968 17031 8 +22137 45259 3 +36952 5369 12 +48610 58801 9 +26067 7388 11 +16049 42189 8 +19075 30567 4 +13647 55862 5 +40304 40566 8 +17333 43968 11 +51661 6339 13 +54288 13642 11 +32056 10854 8 +21783 2379 10 +11566 51782 9 +38126 27662 1 +35190 3584 11 +26041 40710 14 +8142 28481 16 +27274 55274 9 +24008 871 8 +6242 48982 10 +38726 32274 5 +45218 52286 9 +30436 37487 5 +41493 11765 8 +56117 59085 2 +53121 5544 11 +31095 49653 9 +11999 35096 11 +24259 9072 8 +49343 40885 9 +55173 12767 10 +4692 24024 8 +2608 8263 9 +50466 37254 10 +27223 11735 3 +51654 9913 12 +47660 42736 16 +8184 22102 8 +37149 12387 8 +38663 24317 5 +57858 41604 14 +22511 28736 1 +5703 34536 7 +24575 19982 5 +44531 54432 2 +15028 53942 5 +58361 26068 10 +27606 40078 11 +15443 7996 4 +6633 52367 11 +31242 25617 7 +8302 9416 14 +21332 13739 15 +41465 27831 1 +7232 24165 11 +1674 35313 10 +43612 37080 8 +21806 21638 7 +50992 25643 16 +51542 59799 6 +57692 38554 8 +15919 17859 16 +24086 43129 1 +28285 42021 8 +57648 16119 8 +9481 38196 10 +14451 24674 7 +49317 53081 7 +47588 38341 12 +13465 50193 15 +3531 35747 12 +8615 13231 1 +41019 13556 2 +14058 43882 14 +5415 33264 8 +30403 18412 5 +29673 34894 7 +48816 22194 14 +6832 41833 9 +31076 22161 11 +16889 59128 14 +24379 34110 16 +36332 43831 7 +16162 28458 10 +26798 39055 4 +23895 21475 10 +37900 46044 9 +19537 1364 18 +2499 909 5 +34577 59394 11 +40779 26985 5 +40678 21326 9 +48223 6418 13 +42351 32394 6 +23432 37584 9 +51770 6458 10 +54266 58475 17 +30801 32990 10 +23884 20081 6 +33888 12831 12 +35537 27317 11 +16026 48114 14 +23576 55828 5 +47580 36134 8 +29605 16302 11 +39356 5330 6 +6507 13034 16 +39129 42452 10 +40937 41084 16 +48967 40374 11 +53380 10140 0 +38737 36060 9 +48330 33775 11 +3994 19196 12 +38943 6325 7 +46146 57945 15 +31448 7925 4 +28301 3527 13 +55670 7392 8 +34361 50334 6 +21148 48450 14 +40834 7148 13 +55730 12939 15 +9308 37356 15 +21655 16532 6 +57295 48573 10 +10686 35350 6 +3256 12716 9 +1656 58544 10 +14202 5855 7 +54561 50427 11 +37983 39468 10 +54706 59738 4 +7202 43615 7 +38949 12374 0 +53993 2518 8 +43411 49820 6 +36044 31551 18 +56141 47287 11 +20753 42057 15 +43587 58191 11 +53691 53040 4 +20116 41531 12 +47034 25730 14 +50659 26179 18 +56722 46893 8 +30349 11494 6 +52752 34312 15 +57671 59181 11 +16404 31548 5 +24002 20237 9 +13600 59740 14 +12440 54107 12 +11278 7642 9 +17523 33417 5 +33014 4706 11 +36279 15879 12 +57096 10457 9 +15958 29283 2 +9818 57515 14 +14948 47119 2 +23879 19443 5 +47030 37607 9 +16750 8656 13 +34997 51387 13 +2035 52430 14 +41895 43645 16 +12670 28794 1 +32852 58590 3 +33031 33820 12 +48419 43528 7 +47551 27971 8 +52141 10119 6 +46471 44956 10 +40018 52399 12 +54302 4965 12 +17551 19216 9 +25885 42710 5 +10864 4823 10 +37703 2418 5 +38215 53382 10 +9134 21242 8 +26192 16642 4 +50120 59545 2 +51516 23962 12 +48564 42467 13 +15169 10043 9 +32786 17534 3 +13222 47772 9 +34394 583 9 +43734 26714 16 +29115 53217 13 +41706 39588 18 +2252 47303 10 +58390 23789 12 +19416 33131 14 +38856 44090 8 +15121 22708 4 +46439 43201 8 +45902 19696 12 +49086 55571 9 +22583 45146 0 +45997 11575 8 +32992 13622 11 +29457 53389 11 +38216 1007 5 +54789 37742 8 +38801 59265 13 +20325 19228 11 +35801 27078 6 +57492 11639 3 +59895 1908 9 +7290 23454 8 +53245 55356 7 +45310 897 11 +12717 50760 14 +9100 12781 11 +31457 1114 13 +56846 10058 8 +37748 36711 10 +8909 34109 9 +47616 12782 8 +7490 8627 12 +13416 6085 13 +11777 48216 7 +28033 47319 13 +12133 4439 5 +27612 9808 10 +57045 8177 9 +7401 31724 9 +3125 7056 13 +34977 29803 6 +26801 36567 16 +54744 21524 8 +50785 42571 14 +11016 56720 9 +7111 27795 9 +29722 3063 17 +10310 40502 7 +7944 12366 2 +38859 19179 3 +19973 58565 12 +7962 36521 14 +1996 17906 8 +51379 28699 10 +54115 50804 7 +59679 26654 12 +51538 22222 7 +38382 51230 11 +52517 51223 12 +18913 1350 10 +58265 1104 5 +58751 26358 10 +24396 24479 16 +34613 30255 1 +35632 59214 9 +57162 13193 3 +29109 22233 11 +54581 53251 14 +34316 56249 8 +54227 14298 7 +51636 26551 13 +25678 2349 13 +55905 55850 14 +12619 25244 9 +1086 4011 11 +40309 34810 8 +14534 33879 11 +34956 10412 11 +7927 47427 14 +22988 20756 7 +3438 48321 11 +29778 33296 11 +24546 13352 5 +6464 47074 14 +7151 3543 14 +28385 38094 2 +36286 11853 13 +35899 12596 13 +20899 15943 5 +13950 33543 8 +57441 16679 3 +12110 2922 9 +20485 44419 6 +16256 1232 13 +53043 5690 8 +6643 43702 12 +18439 38437 15 +14815 53778 18 +55928 16225 11 +31466 28270 7 +7163 4477 12 +16332 46954 7 +59871 35226 10 +10926 26214 10 +2170 40691 11 +34855 5894 12 +48984 20279 5 +56058 725 15 +27265 11092 14 +55097 39213 9 +29434 36956 2 +30181 43550 18 +1832 33765 15 +38001 55967 7 +54 4985 9 +18626 15504 3 +38061 37901 2 +36477 33563 13 +56416 8508 11 +50346 51918 11 +59869 19821 3 +13588 9080 11 +540 12533 3 +1188 38004 9 +51463 5683 6 +56289 12915 6 +18787 15577 11 +32387 22606 6 +7143 43450 2 +41004 47024 4 +13877 41242 8 +43602 3022 9 +30307 32143 13 +10049 56111 12 +29659 23498 6 +5103 39770 5 +58018 56800 13 +46494 49847 6 +30369 16369 9 +52378 24829 11 +44750 717 4 +35334 59856 14 +18304 20788 10 +38467 55769 11 +10622 30705 7 +2636 56858 16 +19515 40590 16 +53950 20794 13 +6395 38713 2 +29819 11615 2 +57980 27343 7 +26058 55931 1 +58656 39138 4 +16288 36485 9 +6317 9089 6 +38022 3316 15 +2941 25673 9 +52812 47327 3 +39341 34166 5 +36729 1967 9 +1159 19963 8 +37374 22818 7 +51214 15935 10 +27520 13267 6 +30206 28535 10 +36138 32438 2 +45117 5916 16 +44855 4335 12 +20622 55580 3 +46138 13060 8 +29385 24551 6 +5890 52473 6 +13782 56359 8 +54108 10170 7 +2334 21889 5 +38181 24800 7 +13427 25516 8 +41047 12204 8 +39102 39709 7 +52704 16258 10 +18702 34569 15 +39196 862 3 +48193 56411 9 +36118 20422 12 +10816 19300 15 +23486 22232 6 +8907 11794 3 +12685 3068 7 +39258 7830 6 +42494 48843 10 +19913 8877 9 +47705 7950 13 +52431 913 9 +27195 15180 12 +45255 44125 1 +22286 21506 8 +57902 27388 6 +12157 17355 8 +25705 34479 9 +20498 46679 8 +11113 43507 8 +28661 2874 11 +35776 2017 10 +8464 3590 1 +14270 21451 10 +57760 40408 8 +23402 27597 14 +53519 26180 10 +31834 15198 9 +38426 11663 10 +13559 37471 15 +5114 36897 5 +16698 33892 10 +45162 50736 2 +3630 59000 14 +37421 19777 14 +23345 25563 15 +1555 49865 15 +55488 34960 9 +54142 49290 13 +8198 49434 9 +43973 49217 14 +11543 11447 5 +52674 24722 8 +39530 13863 13 +6359 57612 8 +48468 20451 4 +2510 14525 8 +55167 4782 11 +52190 12753 14 +1399 49988 18 +14726 10909 9 +31041 29315 10 +59737 8875 6 +49643 12740 4 +23705 50403 5 +4955 21154 5 +42931 48313 7 +46099 44812 16 +41759 34235 8 +44310 40659 13 +39811 57135 4 +20494 37451 12 +46041 8515 0 +58780 9354 5 +1744 49550 10 +3311 32124 13 +39015 48018 9 +30503 4449 5 +430 30397 14 +1068 37026 12 +57412 8274 1 +42892 58694 7 +59372 46724 7 +52024 31945 5 +28843 4154 7 +10880 39716 4 +12250 38493 17 +55523 883 8 +48427 46687 8 +1063 20525 12 +11837 8414 8 +36456 38264 10 +23277 6876 6 +49539 17493 10 +37372 24571 11 +13522 9752 11 +41184 29180 16 +40159 46409 8 +58579 45684 12 +7135 34666 7 +39778 41777 9 +55489 2131 10 +57184 28515 7 +28859 52567 10 +54230 32477 11 +42275 30239 8 +45493 44943 15 +59627 26462 17 +30892 29445 17 +53722 33889 7 +12142 14545 0 +14939 10166 13 +13040 26158 12 +9028 55712 10 +10584 4525 16 +48684 37441 9 +46907 15455 17 +35884 20515 6 +51027 54187 9 +16777 48231 2 +23059 55736 5 +19740 39532 16 +55986 48416 7 +58335 49862 8 +5368 28158 7 +56045 41330 7 +23164 59137 10 +34533 13760 14 +29086 31687 6 +14148 15587 3 +28220 49209 14 +4083 17401 14 +676 20960 3 +78 36905 7 +15723 50060 13 +1667 47248 11 +48517 44794 3 +56991 34323 3 +36996 9084 11 +36055 34498 4 +36305 39176 11 +11978 21572 10 +1523 46517 9 +31898 56353 6 +12691 51738 2 +37355 16241 4 +29381 46478 16 +15493 16036 9 +49363 39284 4 +6800 52718 15 +34490 6134 13 +50563 18510 11 +36276 42792 3 +21386 42472 9 +22661 59865 10 +52861 13632 15 +5420 18820 11 +15344 24823 8 +12273 5546 14 +12517 26302 11 +47324 52873 4 +46912 52682 6 +9962 58336 5 +47833 26650 15 +59724 30194 8 +42976 17317 16 +23230 31688 9 +24595 52805 14 +4337 10438 15 +4688 33419 8 +59461 10665 8 +49931 59347 12 +55023 12235 8 +57262 32148 4 +55287 34985 5 +24033 43506 9 +11364 40130 6 +5664 18894 16 +53096 47137 12 +19394 37396 9 +14938 3388 6 +11710 47011 9 +58153 59528 7 +31676 23639 17 +506 56051 15 +48545 1307 11 +22358 31894 3 +1975 34547 10 +169 38195 2 +5749 6873 9 +49348 45046 8 +22683 34063 16 +43185 37813 17 +52997 38698 12 +54452 5571 5 +5460 37590 13 +11513 38844 11 +51361 6258 11 +20370 37160 12 +27574 1946 14 +11520 56760 12 +45078 48817 4 +21782 9968 14 +33978 44499 4 +11809 28233 9 +53082 10387 17 +45384 28258 5 +59808 36605 11 +43923 600 16 +6180 22061 14 +47801 57071 9 +23780 44533 12 +58389 55281 5 +38211 34645 3 +5636 8861 11 +30393 53635 12 +51056 31578 5 +32797 25341 10 +27204 7717 12 +26944 35312 5 +44766 42661 8 +40768 13646 16 +52881 17419 15 +26990 34081 7 +26597 13513 7 +17099 34598 14 +13553 40376 6 +32201 49909 16 +19667 2442 17 +46888 55961 8 +45030 33159 12 +3787 47289 9 +20299 29775 9 +43144 25390 5 +14789 18761 4 +37168 55510 16 +27456 16997 2 +11144 13510 5 +21205 55604 14 +59053 46610 7 +46918 12062 10 +48809 20357 6 +32013 16840 10 +32353 27403 6 +35582 45815 7 +5886 40282 6 +35135 53996 17 +20026 8090 16 +54793 40300 18 +42193 33983 5 +32821 34236 17 +33551 29772 4 +24167 37136 17 +53306 23434 10 +36836 43668 10 +25644 28311 8 +5372 19455 16 +1173 25227 10 +45402 28940 8 +6148 37437 5 +10782 55195 12 +29094 49292 4 +21890 34480 0 +7647 17038 12 +57767 37282 14 +26064 40100 12 +19998 29776 10 +20320 25421 7 +37889 44060 3 +23442 59648 15 +17632 1056 12 +10885 59197 1 +20372 51396 12 +2173 28325 7 +21707 522 12 +42713 13956 2 +13839 28038 4 +6755 20821 8 +28464 11038 10 +50848 32267 8 +47144 56193 16 +41856 45648 2 +22790 10628 15 +52649 18524 3 +36597 53615 4 +7041 46351 9 +58312 25850 12 +5896 58094 15 +29992 49504 5 +52482 56904 12 +18892 51481 6 +44000 53730 8 +45682 58564 3 +39168 12894 11 +45414 7671 3 +24643 30656 17 +55846 7124 5 +44350 17834 4 +24898 59616 10 +2002 34374 14 +22923 14158 8 +49194 886 6 +55330 27217 14 +42376 27852 11 +47890 9834 2 +24679 2143 13 +19622 58714 7 +8461 38676 12 +36325 27486 11 +10468 53202 10 +55853 39204 12 +53513 59610 14 +59517 177 2 +20155 46397 15 +38011 11085 11 +47646 55192 13 +4343 1709 0 +19635 7517 11 +34844 22587 12 +31538 45059 10 +50797 7646 3 +30710 25635 6 +26533 12805 3 +42977 26106 11 +35345 33562 6 +47904 8858 3 +27083 16088 13 +27942 30504 12 +10059 4735 12 +16850 50027 10 +42318 28751 17 +43236 19817 7 +29668 12299 3 +22653 55367 14 +8808 45998 5 +503 36264 9 +49287 52986 9 +42687 43031 8 +28826 18636 7 +34559 6341 2 +8536 30956 14 +41188 9776 8 +31293 2647 12 +9232 6133 5 +48483 28896 2 +3232 55008 12 +19483 8777 10 +50298 18475 9 +40369 58205 9 +55027 21944 1 +38459 43025 6 +2033 59034 17 +11051 59943 5 +957 18759 0 +42969 54272 2 +49049 15259 10 +44901 53408 7 +39793 48243 16 +18831 52658 8 +52475 53521 8 +30743 40818 11 +58381 48729 5 +42531 2164 5 +44081 45176 18 +9633 29362 15 +13140 18107 8 +24270 36327 12 +10806 9801 5 +24993 8779 5 +48836 48080 16 +26444 36158 8 +5701 32727 9 +11980 6357 5 +16326 17826 9 +5942 59007 5 +26951 53294 9 +13668 35669 10 +55098 52506 13 +56226 4024 8 +10263 50241 13 +37541 2463 12 +33360 55456 15 +34521 35314 6 +7780 30123 2 +6210 37682 13 +29059 56101 2 +18965 35924 11 +13742 47228 11 +36943 16703 7 +15326 36205 16 +11359 32436 11 +53683 59192 15 +21765 9846 10 +54990 47273 10 +46660 869 9 +15925 14171 7 +57625 18220 9 +25830 29014 10 +36829 15464 5 +27993 19733 16 +24182 25667 11 +2177 31273 9 +15492 15101 3 +42627 38038 8 +59279 48882 16 +21742 43951 3 +43673 16683 8 +18659 43539 2 +57583 13366 2 +15566 25261 2 +40602 22183 11 +33796 20814 7 +9050 54057 17 +41988 41863 9 +17475 44173 17 +11637 46948 6 +58178 56515 11 +35324 3919 10 +6126 49477 5 +18399 48245 14 +30606 34455 9 +27230 34163 18 +43590 31675 11 +59866 56542 13 +27484 59280 8 +42003 43966 17 +1984 43075 16 +8953 33497 15 +38977 37180 13 +39395 31220 14 +41562 23154 9 +35621 43083 1 +21897 43488 14 +17817 50164 13 +9994 49528 0 +52866 16213 12 +18642 16749 8 +3573 43273 4 +20384 20445 10 +52882 53791 2 +40022 40970 12 +46125 27014 4 +32023 21501 12 +49177 2477 16 +3943 14367 3 +12802 34356 2 +22750 46287 13 +48522 10799 13 +4029 13518 9 +32939 28172 9 +29471 58742 9 +29379 28753 18 +56540 21096 6 +5611 1069 4 +58244 41905 11 +47275 21760 2 +40538 27495 10 +58698 35418 13 +44392 8832 11 +22503 781 9 +7389 46514 13 +9369 35636 15 +34926 49060 7 +58349 51026 11 +17137 6204 4 +37844 33452 8 +43600 8595 5 +26327 17553 11 +23199 14483 9 +57164 25127 11 +55541 19491 0 +58489 8257 2 +53364 38806 5 +39482 20977 12 +43531 35249 7 +3112 14979 7 +35478 15592 11 +47797 53507 5 +12936 24942 17 +44433 50262 11 +36898 55399 3 +25145 50371 10 +35556 47825 14 +17689 166 13 +48556 34919 7 +48442 267 13 +11798 43767 13 +48486 3524 10 +13154 18019 2 +55629 26262 2 +2782 43697 6 +2098 55110 3 +57290 6581 15 +40386 17089 9 +56917 53422 8 +47564 333 14 +39247 48273 10 +25367 31881 17 +26289 56970 12 +48112 15162 10 +51833 35793 1 +57630 13028 13 +22819 21639 14 +6427 6943 11 +4349 39127 9 +7144 30331 5 +43754 39409 13 +36654 9347 16 +55682 5189 1 +52068 35304 6 +13336 17063 8 +56530 22416 7 +29003 54336 17 +9447 17295 12 +43868 18954 7 +22234 45817 3 +58 11611 12 +52171 20715 10 +17502 9830 7 +59226 10265 6 +32543 57125 7 +22070 42041 5 +56649 57533 12 +47671 59667 11 +51485 51068 13 +36197 582 7 +45919 31066 12 +21428 3353 11 +15 20900 16 +52327 25978 3 +13766 10517 11 +46033 21548 9 +27710 20689 18 +38572 18371 1 +27861 53016 4 +55548 55951 9 +45223 34493 9 +5205 35157 8 +1886 57511 11 +28871 22547 12 +7096 31990 7 +14430 1714 2 +22968 27725 13 +39668 57978 15 +8381 31136 6 +57646 14377 13 +57311 3313 7 +43198 35989 7 +24135 25622 6 +2043 17470 11 +5006 16116 6 +48914 51804 13 +22540 20203 12 +28900 28120 10 +24841 34295 8 +31213 43703 13 +4448 20233 14 +5384 9509 8 +21660 43313 10 +38008 4921 5 +43098 6293 8 +17208 31984 7 +12612 12074 13 +41824 49144 5 +52717 45142 14 +10779 53433 8 +37906 38463 10 +10052 54967 3 +22809 24334 10 +27652 4026 11 +59050 24504 14 +45330 31209 5 +54366 9684 10 +19690 988 13 +10277 27267 9 +26973 11916 13 +13030 23220 7 +40684 54312 16 +22059 7368 13 +53283 24014 5 +18307 57599 4 +3479 55596 1 +38899 45241 15 +45056 38353 17 +58869 13195 14 +49628 51391 9 +28554 10316 11 +25570 57547 9 +24784 40389 3 +39177 55386 7 +24852 2949 15 +10295 6453 13 +38692 52959 4 +6467 40604 4 +58210 2290 8 +5310 6508 14 +13269 15084 15 +33526 16994 10 +15328 43220 4 +32270 41853 16 +554 13865 11 +40459 28694 9 +54723 21850 10 +7846 21882 4 +51134 18495 13 +6452 45837 6 +11435 4581 10 +24649 2806 2 +51236 17188 9 +33493 35746 4 +50185 59751 8 +56420 35410 5 +19396 5161 12 +28113 55660 15 +15105 26190 2 +216 33520 6 +33546 33308 17 +34789 14619 5 +54716 42430 8 +56244 37114 9 +6089 20890 8 +47312 13141 11 +24391 9547 8 +21608 56689 1 +8096 35779 2 +56296 52826 13 +46890 56348 14 +31228 47297 14 +57578 47042 6 +23493 56262 6 +55324 26978 6 +25101 26288 4 +58446 2011 11 +43298 40903 7 +24029 56928 14 +52111 13187 10 +49001 20693 9 +55644 22398 2 +27964 48265 17 +35745 4329 16 +48895 59827 1 +20500 349 10 +29836 50986 8 +48636 56943 12 +38548 11529 14 +55555 49263 8 +24105 44576 8 +4574 17103 5 +27271 56192 6 +17692 26481 14 +11890 31173 8 +52326 24842 5 +54900 25927 2 +22011 7487 7 +52175 52595 10 +3567 33294 6 +54669 48472 15 +18242 26994 10 +20343 10560 10 +33987 23409 6 +57111 5539 13 +41555 5049 8 +34080 50426 8 +36957 46529 9 +17037 36585 11 +30988 38421 13 +21734 10447 13 +34760 15543 9 +27222 57670 13 +27080 48501 11 +59803 56403 10 +35112 45148 6 +4156 47708 7 +32837 11642 15 +46519 58426 17 +38198 59282 3 +58370 22705 7 +24514 33846 8 +1414 7610 13 +24838 6247 2 +8778 18397 4 +43103 8830 6 +43553 3823 8 +28299 20805 6 +30358 11025 14 +15438 21559 4 +56646 2687 12 +44921 24977 8 +3551 35668 8 +37276 54653 7 +56213 38272 3 +46507 57059 5 +58323 32958 3 +48669 40427 7 +13659 42715 14 +57082 59859 4 +48655 26285 14 +45761 16582 9 +16876 2256 5 +17782 17363 10 +2024 19121 11 +9999 58700 10 +18449 48407 15 +22549 58324 12 +45715 40780 7 +45602 54299 7 +28702 26010 13 +29883 18308 5 +45058 57832 8 +49583 29069 1 +168 24192 11 +14228 30756 10 +37880 43418 2 +14267 18207 3 +157 40555 6 +12443 15596 11 +21187 41498 8 +43829 27617 5 +17172 31226 14 +43005 18395 9 +49459 29792 4 +54519 26252 8 +24760 1745 16 +13487 34308 3 +8298 2693 6 +11240 15912 9 +12804 20301 12 +50499 37714 8 +1132 1866 7 +5761 32341 11 +20602 18891 2 +54675 50976 4 +59202 40478 8 +52527 50463 5 +2081 13369 1 +40013 33639 11 +48460 31561 11 +24404 56080 12 +16261 14355 11 +49508 47631 11 +31914 27425 15 +50907 45564 5 +15280 15730 7 +49777 47015 11 +1579 36024 10 +31503 49269 5 +51161 7109 13 +9662 40826 7 +13805 7350 13 +16481 23003 10 +25765 9125 13 +21057 11933 4 +48731 27765 9 +46582 6536 4 +5342 47491 4 +46224 22384 8 +3420 18613 10 +32504 343 17 +31060 15188 14 +4504 28226 9 +4377 21070 10 +35201 47993 5 +14003 36298 11 +49128 51154 12 +57080 3722 10 +4952 13656 7 +55095 18565 1 +51817 1680 5 +10367 2472 4 +29152 29253 7 +2966 46526 11 +48975 46391 2 +45432 5863 9 +50013 43591 13 +45032 29800 4 +5043 56281 12 +13404 16254 6 +45522 55917 0 +43651 53925 9 +50380 44546 10 +28740 50607 8 +31487 19941 4 +26970 44754 15 +32452 56745 13 +35911 8757 8 +55397 51184 9 +56574 27979 7 +26884 36372 12 +33393 46080 15 +43525 25825 9 +23188 13051 12 +6383 24804 15 +33545 37679 10 +12758 32118 12 +23825 14829 12 +15333 947 13 +32033 46880 10 +33251 41222 9 +12283 8179 10 +30860 22448 8 +8223 12184 0 +12108 32251 12 +568 30004 8 +17768 22106 9 +54306 56100 4 +46411 47654 9 +32719 32403 13 +21078 12214 3 +10615 36845 9 +39422 38666 1 +39603 35161 3 +21999 42454 6 +51132 13102 10 +27543 19846 12 +42115 52459 7 +44172 47271 8 +9329 17492 4 +16852 48934 9 +2544 43323 6 +52493 14731 14 +7533 8171 9 +12076 10111 14 +49867 8516 14 +28662 13449 9 +29592 24288 8 +30509 40192 9 +22636 50881 5 +31543 27565 13 +32407 16218 9 +23140 36005 10 +16887 14348 8 +44760 34495 7 +27980 59821 8 +50336 57854 12 +14984 29138 15 +43390 30652 14 +29447 49218 1 +14500 9738 11 +29815 14555 7 +26979 50351 7 +39348 25100 11 +23425 47905 4 +53021 53679 14 +12722 57839 8 +41671 53155 12 +54398 51729 9 +56199 21948 12 +31871 32325 7 +21485 57769 6 +8496 55451 16 +21595 51926 13 +3577 37376 15 +4542 15545 9 +34649 50139 9 +35258 3550 7 +39372 12668 13 +2576 17152 16 +36547 19086 14 +19064 43063 10 +6886 47104 14 +45499 59950 9 +7763 1757 17 +14786 43735 9 +29414 19280 3 +7848 19256 14 +30259 47110 14 +40077 12078 8 +55526 25585 11 +31997 661 11 +59930 35266 4 +28589 18484 9 +55166 28340 11 +59963 57370 11 +6812 26717 5 +59654 54874 14 +13283 49035 2 +16778 38489 17 +57049 48075 9 +34522 5909 8 +55869 5033 7 +32847 38790 5 +8312 4770 12 +9077 12427 11 +6645 56427 2 +27316 476 5 +19565 49591 9 +50822 27502 12 +27738 49038 9 +15718 58847 11 +50370 21194 9 +59566 45920 11 +20405 24811 9 +17293 46089 1 +2888 54562 9 +33157 11334 7 +23523 27955 5 +55035 9605 8 +17625 54972 3 +5308 5007 7 +12534 41089 14 +3047 13618 11 +23361 17664 6 +58339 30703 11 +49839 20174 2 +46873 48093 14 +20126 52912 15 +16591 45529 9 +16349 1033 8 +25821 41210 10 +58746 8026 13 +14473 57073 6 +3808 51213 12 +26287 34056 9 +20332 59304 8 +36747 22889 14 +45527 55278 9 +53872 17925 9 +4871 11224 15 +56834 59422 3 +29615 28082 8 +26718 41823 3 +9143 3875 12 +39765 12143 12 +30576 10654 12 +11279 57817 4 +19533 7014 7 +41873 59108 12 +1148 13605 9 +40262 58942 8 +10600 40390 6 +13852 7260 9 +21395 15045 11 +55762 52797 8 +52827 9146 12 +37410 17308 7 +34463 52499 9 +32266 32785 7 +31893 36724 15 +31514 58772 5 +8519 2396 5 +38192 8138 13 +26865 8020 15 +31767 13749 14 +56152 43704 10 +10970 48696 11 +32372 5635 6 +32314 40524 10 +22241 35130 15 +44953 33774 7 +18723 56043 8 +58238 45977 3 +31301 26616 13 +43148 4219 14 +48443 55369 11 +31851 28322 9 +20253 22165 15 +26404 16372 8 +45214 25220 6 +56040 44467 10 +48661 44253 5 +442 46277 6 +6731 49566 11 +8652 37794 5 +47419 37464 3 +33874 13621 6 +56409 36252 13 +11844 513 7 +39721 41382 5 +22724 4887 16 +21849 39328 5 +41312 54193 12 +31744 24053 18 +44201 56458 15 +16429 48170 7 +59186 5409 10 +59496 16333 14 +58975 1675 10 +21052 17221 7 +40772 42774 13 +44624 51744 13 +58852 32732 18 +57393 6620 8 +51129 34895 5 +6994 33342 10 +50476 57677 4 +32456 15281 11 +4331 14124 9 +25884 13257 6 +27341 37737 16 +28167 30409 1 +49260 16045 1 +16129 45725 7 +8144 33163 7 +33437 23453 11 +4359 1897 3 +50208 40494 0 +39702 35032 16 +4030 43793 14 +48837 13293 5 +20213 7213 10 +2151 18469 8 +19038 42966 3 +30833 16025 5 +7863 17719 11 +18964 42999 4 +58453 18910 14 +18525 39645 11 +37749 1101 13 +53157 49171 4 +37390 42843 12 +16493 57690 10 +5578 21870 12 +6491 25059 15 +2006 25113 15 +20244 57865 1 +11082 57910 3 +18549 4579 6 +57660 42742 7 +41617 47550 8 +29796 28513 8 +59159 6347 7 +53799 37967 4 +36293 47477 10 +54454 37659 3 +18202 49445 9 +58681 18629 15 +43603 25787 7 +30806 23358 14 +949 46748 0 +28619 54655 9 +2087 57265 6 +20991 7469 8 +45857 15100 4 +52468 1478 10 +53911 29043 9 +41060 37868 14 +25539 12313 5 +12635 12979 7 +27974 48255 17 +28334 12880 1 +45421 23127 16 +50084 14313 16 +38592 21388 12 +33102 53608 8 +43937 58612 8 +52465 49094 13 +59229 11399 10 +33582 22250 14 +40618 3247 3 +48543 1099 5 +14536 25319 14 +9795 55901 5 +59360 20522 9 +49698 11020 14 +47995 38266 10 +3170 54448 7 +10356 36243 10 +38776 8251 9 +41714 17311 13 +14220 32495 7 +28089 52207 6 +21226 3536 8 +48252 54348 10 +49966 13910 5 +32914 16231 9 +31989 46501 10 +24388 42997 7 +5296 46082 10 +3593 25896 4 +52552 14746 1 +52204 55599 9 +30063 47171 8 +33726 18955 7 +32718 19031 3 +53747 52253 6 +9663 52673 3 +19013 56967 7 +15763 32952 1 +25396 9463 4 +41474 10347 3 +40125 56517 10 +37509 18594 11 +43407 10197 10 +5704 26572 14 +51368 25799 12 +1210 34599 12 +3053 14037 15 +6685 8473 4 +39646 6787 10 +27895 41548 6 +44030 59487 0 +43979 56916 12 +27622 16630 9 +23812 35542 6 +25861 9170 8 +38442 12806 15 +52173 7597 7 +8314 38153 15 +49339 22470 6 +31544 39516 8 +46283 32384 11 +2121 52220 1 +32471 16432 16 +40392 18228 13 +53407 23416 6 +3073 51136 9 +19088 19983 8 +37295 32192 7 +44994 52388 6 +59225 46286 2 +43918 56383 12 +4262 1043 10 +49761 25197 10 +54897 41661 8 +19776 35874 4 +31356 41699 8 +26037 44982 14 +16998 12373 13 +16364 32018 13 +57155 6697 12 +35840 10652 9 +22393 44430 14 +22579 44131 3 +52519 42204 11 +7970 59114 7 +11407 6095 11 +53808 17328 7 +42056 57633 5 +33598 13212 8 +27925 7684 13 +48857 54207 13 +13864 13131 11 +13325 28874 8 +12185 8470 9 +54122 50862 5 +32029 39659 16 +58499 42570 15 +13887 34982 16 +9880 22345 5 +26652 40641 10 +1126 4888 14 +12268 10494 12 +3760 41701 18 +16678 38237 11 +34100 3150 9 +35485 2071 4 +4801 10930 11 +21757 15354 18 +11159 48898 9 +33872 32590 6 +40423 48145 7 +39850 36997 1 +6569 53071 13 +18276 10281 13 +45785 29435 13 +20311 57664 15 +38999 36182 17 +23284 36923 10 +48911 57202 0 +31515 13288 6 +34257 44675 8 +49711 23112 14 +55859 43678 15 +22506 20836 9 +54984 48567 14 +17056 6921 10 +49117 56578 6 +7221 17014 7 +57999 53127 8 +20504 24093 12 +23604 48347 10 +23072 32533 11 +27027 21635 8 +11829 26568 14 +12585 49597 8 +35368 50882 18 +46009 37228 13 +20751 19926 2 +23875 45013 6 +53721 35920 15 +47919 29527 11 +6235 8587 8 +35965 30737 8 +6535 1269 15 +42717 3965 4 +4873 33429 14 +33304 55131 16 +40441 5145 6 +2283 22335 4 +40128 47979 12 +58316 29509 7 +55134 30327 10 +58296 9974 11 +52006 52964 9 +48854 7880 10 +51943 2216 17 +50875 20047 3 +14563 16675 9 +8159 40714 1 +1839 12351 1 +50680 709 3 +46629 2137 17 +10164 35680 6 +57725 29707 13 +3800 14883 4 +20292 9076 8 +13899 7932 8 +4238 42690 4 +31467 7947 11 +14749 56145 8 +44730 35979 3 +58173 15526 9 +49728 28559 7 +35810 55289 12 +5676 32019 8 +4702 53636 14 +12705 31998 7 +477 30984 5 +25932 3674 3 +46457 11510 14 +57334 35076 9 +33287 41760 14 +29918 17506 8 +33069 16685 5 +8862 13736 9 +54242 29661 10 +8117 7812 13 +25112 27338 7 +17642 31839 6 +36509 36558 2 +8738 13452 3 +26778 33836 14 +55468 55291 16 +31225 28625 18 +22770 44782 6 +3067 16463 9 +2709 13745 3 +17421 19988 11 +17997 17042 4 +8733 31617 8 +6046 47856 12 +26490 16237 8 +50030 18260 11 +12988 45767 9 +39333 14788 13 +18755 25283 14 +4808 3222 7 +11882 41939 6 +1250 48225 18 +15900 26359 16 +35481 12 3 +15696 14992 2 +19251 44139 14 +54161 16438 6 +17948 7760 10 +1706 25020 8 +9449 35900 3 +47938 56645 8 +40853 28319 11 +12300 40735 4 +47573 36253 7 +3030 25326 17 +17764 2798 15 +45009 38810 11 +14482 11565 7 +11757 19921 10 +39942 53656 11 +43252 6404 11 +50951 47070 5 +52751 1282 12 +32861 53413 12 +52392 40872 8 +21972 55125 10 +28779 52018 17 +34042 57868 11 +49259 48272 17 +43866 47869 7 +16264 59400 12 +37454 30651 3 +19624 4661 13 +29262 52804 0 +50029 17207 12 +20719 20654 1 +11473 45556 8 +52398 43724 16 +9850 1122 11 +36363 6282 9 +49500 3792 8 +5031 55458 9 +21054 57586 1 +57504 46284 16 +58345 39216 8 +55297 45183 9 +25464 8566 15 +27145 55989 8 +36848 16594 7 +36255 48994 6 +32892 35932 9 +5187 51162 7 +20675 2829 7 +20970 4293 4 +57317 908 8 +20506 2158 7 +22955 57741 15 +38596 50987 10 +54481 17671 12 +51075 4418 9 +2617 16174 5 +9415 30111 9 +4677 12918 9 +39486 58301 10 +44762 4203 9 +49910 22192 7 +59937 9022 14 +34542 10765 4 +35154 24617 7 +21478 53212 7 +48258 4526 9 +12495 1420 14 +49314 50791 10 +31541 52159 12 +36948 38764 1 +40495 24878 11 +46634 34620 5 +24252 56718 11 +31690 1618 14 +50458 21827 18 +19574 16764 10 +38228 20085 0 +31801 51231 13 +29553 18129 17 +4899 39429 9 +18512 14982 13 +20823 3565 8 +51555 44039 10 +48773 1537 12 +48025 38920 7 +41097 17180 10 +44303 2590 9 +31244 460 18 +52078 8822 7 +4809 4974 12 +38036 29446 2 +56669 15257 11 +58821 45189 2 +56833 23242 7 +49077 11948 3 +2879 5235 3 +49819 20926 5 +6014 32245 8 +17981 52366 7 +33165 18869 10 +30366 7798 10 +5805 39914 6 +1895 47828 14 +16989 42515 10 +46504 47054 9 +47522 8837 11 +20456 14835 3 +55508 15828 2 +3648 12170 11 +50332 18157 10 +14286 42269 10 +2016 45409 14 +27802 2042 8 +56119 33441 6 +33459 49233 13 +2359 21309 8 +50356 55455 6 +33877 25571 5 +23047 38725 11 +16478 11607 8 +51025 59915 11 +58882 59375 3 +56684 38105 10 +15325 56438 7 +32593 49667 10 +35160 51987 12 +662 3517 8 +16674 15199 8 +51525 34870 14 +27870 47895 6 +30507 6754 9 +40103 46425 3 +51371 27000 10 +26145 35789 17 +30178 46248 13 +32165 3973 4 +16380 39993 14 +13633 5827 13 +609 20671 3 +39031 29784 4 +49533 10893 7 +18164 42711 6 +47447 54740 7 +42611 34795 8 +41385 19114 6 +47133 30777 14 +9261 24899 8 +2637 10817 14 +32156 30420 7 +41572 48106 14 +47664 23039 11 +58756 27815 14 +48701 32830 7 +49894 6013 6 +59145 18163 7 +10373 9033 10 +1875 1482 14 +27528 53355 1 +15835 37029 10 +5733 37158 2 +56691 49286 5 +38 55182 15 +25714 54177 1 +23862 51290 1 +22864 28203 2 +18783 8368 2 +19646 35321 7 +6038 38015 9 +4479 58131 15 +54466 29095 12 +53853 37419 13 +44040 33556 1 +23611 34297 17 +6193 29634 12 +29862 51717 3 +50010 51337 9 +7299 2555 12 +27196 23392 9 +36555 32553 11 +37946 624 7 +13348 10763 12 +16621 31691 12 +18360 24808 2 +50080 52342 5 +39099 4588 3 +371 5468 7 +15273 6071 8 +48815 6947 7 +35356 56699 6 +16278 1093 1 +56018 35223 16 +21809 34593 4 +46101 9683 15 +6641 31283 12 +52199 24077 12 +46209 32252 13 +35662 40193 11 +7334 45015 10 +519 6652 4 +39891 21692 6 +26360 46878 10 +48578 58647 0 +23545 42370 8 +17574 17096 11 +39238 24146 14 +54886 21203 1 +31738 6532 12 +26676 59705 6 +45706 24232 13 +20093 29096 11 +15470 16633 7 +19837 15776 2 +15279 47673 8 +33228 3473 1 +809 34260 7 +15948 38320 9 +52177 45027 9 +42202 16979 15 +37491 7116 3 +42987 6781 13 +2673 55653 9 +6751 28008 13 +8670 18083 7 +46396 3717 14 +20018 31420 2 +14535 59863 7 +52671 55280 12 +30719 13871 11 +42402 1722 3 +1083 16586 14 +6056 33281 4 +39963 47566 8 +49634 24570 10 +31278 38566 9 +17650 41468 9 +9775 29582 8 +8040 37507 6 +1500 15530 9 +58697 46466 11 +9357 8383 10 +42130 18310 16 +12913 15362 8 +19660 50713 6 +31994 16295 9 +17460 7855 3 +34215 47000 1 +19723 48493 12 +16790 59334 11 +12199 39612 6 +50310 51586 7 +7720 58257 4 +33570 53086 13 +14899 56880 8 +14048 44480 10 +40644 25712 10 +25658 37808 10 +9680 50577 4 +15743 12732 3 +16650 22880 9 +39427 40791 12 +16039 37709 17 +18827 37467 3 +30717 58509 12 +24640 40455 9 +56770 18899 5 +59184 56826 13 +8074 34941 13 +38403 43142 3 +28053 22697 11 +18518 36127 7 +35244 23390 2 +48462 38293 11 +43568 13448 8 +24621 46190 10 +25534 16474 4 +33268 55612 10 +18691 41499 11 +38464 20839 7 +55495 134 2 +23443 33761 11 +10134 56615 4 +40904 27700 5 +1893 20094 9 +18008 8678 5 +58052 56867 9 +2751 41890 9 +6277 17795 8 +11658 42683 6 +36224 7104 14 +44279 7746 5 +22010 15317 8 +6042 52102 15 +40846 3930 6 +52354 18170 7 +12545 5014 10 +1936 19860 10 +26708 25139 10 +51381 36300 11 +15213 44619 7 +22716 653 11 +44976 3084 14 +21997 39472 18 +52885 51504 8 +7251 30813 12 +56980 14778 7 +26078 3788 15 +8322 47592 12 +43160 42810 9 +38756 28421 12 +36505 5315 5 +18043 53023 16 +40465 48212 9 +5723 18451 8 +33288 15557 6 +2351 10286 14 +57724 17728 10 +2301 6215 5 +49852 21921 2 +45884 9912 10 +31815 21625 4 +23296 8856 13 +16669 50995 11 +42535 31748 5 +38579 21788 2 +12818 42874 6 +13299 1852 4 +12059 9868 12 +39180 35846 12 +21845 37597 7 +19155 7728 6 +52249 9321 11 +48196 44512 7 +59391 38045 7 +38593 29639 9 +58877 59603 13 +58294 43327 12 +25975 49472 15 +6510 6090 13 +23714 3019 5 +21251 53729 11 +57771 23852 4 +34296 57213 6 +39274 42274 10 +35674 45951 12 +27549 17241 3 +44397 46049 9 +15694 24393 0 +58183 32539 6 +26837 57555 16 +44305 39076 4 +50357 14682 1 +36257 26447 3 +58845 39225 10 +11013 28814 2 +42441 33180 5 +36184 19826 14 +33984 28376 11 +35355 9042 15 +41314 48248 7 +52949 33886 10 +59493 34112 11 +36001 36422 3 +53391 125 10 +44600 45616 14 +46891 43916 14 +11169 31039 11 +48056 48048 8 +20459 40656 10 +17909 30044 2 +8133 56341 11 +36967 13612 9 +24754 6470 14 +37508 44926 16 +57870 36821 14 +59507 14262 8 +2613 40734 12 +34922 20331 6 +8094 47423 10 +17893 43241 5 +22150 55283 11 +6725 13372 3 +37577 8387 6 +46405 6549 10 +18243 3229 9 +11498 40261 15 +56178 44243 9 +51218 33666 10 +37731 40046 11 +5800 37608 16 +41718 53997 16 +13817 1771 4 +36380 15706 7 +13431 6587 13 +18850 47487 9 +54226 59846 13 +48051 12893 11 +53715 29586 6 +6726 5974 9 +20567 32104 16 +17197 15439 9 +6741 5630 10 +14934 9439 9 +23573 46659 17 +16005 24301 17 +44340 50668 16 +1121 16627 5 +54686 57809 11 +47499 44573 9 +38597 2737 13 +17601 43358 15 +52066 59142 6 +49099 25031 7 +24123 48217 13 +26581 45387 3 +42795 20259 3 +17000 3470 5 +15681 20328 11 +25118 55673 5 +1196 27163 13 +30266 47468 9 +26830 29963 10 +36270 44920 15 +4049 34284 7 +25169 31920 5 +3009 25138 6 +3317 54891 14 +34169 50796 8 +25332 11674 7 +49025 54516 8 +21648 32401 7 +19215 31948 9 +26381 20016 8 +48317 30999 14 +45601 9676 10 +57152 36240 10 +7652 9693 5 +46446 22246 9 +37065 41138 3 +6604 46862 13 +11808 43253 17 +14273 28689 11 +51464 32289 7 +43598 50644 10 +40520 53010 12 +17665 7626 8 +17592 53727 6 +18983 24415 8 +13932 2958 17 +32996 1258 9 +18018 33052 14 +20389 9200 16 +53205 11167 8 +45847 14733 12 +15607 5271 10 +42978 17849 13 +26690 20875 3 +3611 41803 9 +34227 41771 18 +33444 27755 6 +32909 6223 17 +10558 23529 8 +41434 21843 16 +33125 3596 7 +13987 7706 6 +35455 33037 16 +17262 16104 3 +24719 29662 6 +38018 26668 14 +42621 5021 13 +41427 36891 10 +11044 57344 11 +53314 53256 1 +38642 1315 9 +22581 33865 6 +14426 27929 13 +54916 12575 8 +38704 7624 11 +658 12413 13 +18980 18056 5 +4119 28527 8 +57131 49249 6 +59323 23037 8 +50055 25860 7 +48611 27546 8 +31959 16462 11 +42105 47065 9 +6611 55715 3 +7501 11949 6 +58641 28006 12 +52641 9212 8 +43375 59748 13 +37500 28347 9 +41564 59842 15 +56662 59633 9 +39314 20634 11 +20914 36772 11 +45024 45874 13 +21720 54856 6 +33572 2096 12 +900 30298 13 +4104 11466 11 +34937 29426 10 +48049 15297 8 +27122 14409 11 +57636 1266 15 +15214 5212 13 +18692 12786 5 +37727 44072 10 +28184 59433 1 +53045 15758 10 +26642 7065 10 +37718 1736 12 +3331 19109 10 +8237 1403 7 +26272 3342 9 +2284 7761 10 +29155 4178 9 +35009 36195 7 +40 46657 9 +11691 15303 12 +40305 16571 7 +6145 17836 11 +21592 44612 11 +43897 43625 7 +38232 56381 7 +3521 33418 4 +42653 30581 12 +37793 11217 4 +53822 59223 7 +11102 20080 12 +15465 4094 10 +47558 18092 8 +12149 54672 11 +45551 36181 16 +13629 6118 6 +885 39001 16 +27914 453 4 +28995 7813 3 +24233 42101 9 +28447 9482 10 +3603 25646 6 +19588 49895 5 +39239 38773 9 +50909 51756 3 +57357 34907 9 +22780 51587 9 +59055 32518 8 +31885 8272 4 +39454 11160 9 +11309 39723 11 +34332 43595 10 +18572 10798 5 +12073 57752 10 +31794 42798 9 +31280 18515 1 +28152 58507 13 +13586 39246 9 +35598 19527 16 +53048 33640 3 +135 44395 5 +9361 12437 11 +6521 34585 2 +15841 40611 4 +11280 18404 14 +36083 40468 10 +14385 59739 15 +58204 20128 7 +41591 18508 6 +5568 10407 7 +12848 14519 15 +44077 21988 10 +49679 54936 13 +40900 5423 7 +28562 47216 8 +24132 11966 8 +15310 14452 12 +12646 18278 9 +17917 25914 7 +4502 7440 2 +32137 54253 10 +44589 54621 6 +35370 55298 6 +2487 33559 12 +8943 36064 6 +35470 29855 13 +19495 13786 10 +36362 42465 9 +16262 55219 7 +31747 39816 18 +46686 48637 12 +7655 28248 7 +48368 32999 7 +41233 24336 6 +58466 10386 6 +31150 29408 4 +50070 55674 8 +22140 57381 10 +4382 43406 5 +21296 3235 8 +42693 37862 3 +23914 42658 0 +45035 2432 1 +11619 38924 5 +18732 2680 12 +49916 2264 6 +9271 32223 5 +19757 13354 17 +19561 25268 5 +19712 31657 6 +55843 407 12 +51764 4322 7 +25075 16445 13 +44140 36470 7 +18058 59090 14 +6334 58851 11 +15591 11004 7 +56767 50826 8 +32928 48186 11 +40609 50086 12 +25239 5653 14 +35318 5434 9 +51062 34291 8 +43692 53990 12 +24856 52156 6 +31141 45968 17 +4933 19410 2 +10594 50195 7 +6673 19407 6 +45398 19408 9 +47329 32 9 +54404 52551 6 +19984 28570 11 +44259 19372 15 +14542 22403 8 +40667 5891 13 +8876 52232 14 +51777 48268 0 +13671 18496 10 +53458 12667 7 +4973 51718 14 +11233 52928 3 +38690 56504 12 +45711 1625 5 +50280 44427 14 +45184 54410 8 +46431 9564 12 +50 39941 6 +15535 8384 9 +11032 18023 8 +9570 59356 4 +25556 42620 12 +18812 29456 3 +31565 35964 13 +8350 29265 4 +29849 3072 5 +36814 44803 8 +22495 2393 5 +31279 1229 8 +19405 21629 9 +28436 53576 6 +26459 51934 4 +19742 37537 8 +17098 30921 10 +6428 12833 12 +2659 27284 8 +42572 14711 7 +43153 29629 10 +16565 24845 9 +28620 21049 7 +42192 44889 12 +51892 53511 9 +48673 20967 8 +21280 29631 12 +16753 21649 17 +49075 37595 8 +28228 24669 6 +40023 3417 10 +58839 5090 7 +28967 24689 6 +41433 28129 18 +30926 5062 9 +24853 33850 3 +48209 539 9 +11077 38789 4 +56702 33579 17 +32374 27875 10 +48766 44854 18 +39012 3248 1 +18145 27183 7 +3730 44819 13 +25843 41912 14 +12557 9410 12 +39947 24803 8 +39531 20576 7 +4414 48851 3 +36346 18730 8 +46775 22901 2 +21161 47223 10 +50127 33637 4 +56033 16133 12 +54807 48763 8 +25760 38735 7 +38303 9225 10 +32907 28876 14 +31260 55057 14 +38389 3356 12 +55037 10271 10 +4930 17754 9 +6542 24954 17 +17405 42739 15 +35294 1040 0 +9756 55815 11 +47697 6127 5 +33066 27603 0 +27205 40295 9 +22500 4998 3 +33496 7156 3 +15768 47847 11 +32464 21398 7 +35565 10850 5 +48782 12654 8 +40776 21098 8 +49576 130 3 +6463 15911 9 +19175 45611 9 +33990 32752 15 +53004 8792 7 +49551 2049 12 +33310 18966 8 +11426 8524 10 +59464 46115 11 +29846 18021 18 +29040 51454 5 +31009 39041 8 +56140 27835 3 +4644 55084 8 +17656 7670 14 +31752 15194 15 +30842 42881 6 +29981 13237 11 +22808 3300 10 +36770 2991 16 +2540 44942 11 +39267 13812 11 +8207 36475 6 +42434 22175 11 +31974 34545 10 +54204 52691 6 +46135 21427 9 +54582 28171 7 +6093 12028 12 +39652 39871 4 +7125 8033 15 +58578 42612 6 +37791 48520 9 +40431 7587 7 +41783 52711 17 +37403 45689 11 +10801 36256 5 +38497 22605 0 +48956 25049 2 +58938 10482 12 +52494 25732 8 +50806 45854 12 +4598 30489 11 +16265 24158 7 +24446 45101 8 +17582 34619 3 +39561 51247 3 +9769 8770 14 +50973 56682 11 +7428 28802 10 +28781 42568 9 +31328 50823 11 +19595 21287 12 +11678 40645 14 +30574 5957 4 +8192 26357 5 +37469 17611 2 +3224 53302 9 +50928 27296 6 +51064 10540 8 +45869 25771 15 +42384 3578 10 +47426 35375 11 +42898 45812 3 +40110 21163 12 +10065 40269 14 +25316 2117 14 +5170 44636 12 +34013 35555 16 +18062 35323 12 +15637 3996 1 +33552 32809 6 +34879 35348 6 +51115 56526 12 +56067 38222 8 +22181 24315 14 +18521 3977 17 +30986 35950 11 +56374 23840 8 +15210 45937 10 +40782 18039 5 +58610 16618 1 +41773 10034 6 +15453 11983 8 +13862 22517 10 +48746 43828 11 +41669 41616 1 +37394 35442 11 +23246 36893 13 +22633 10728 9 +50392 8665 14 +29266 53250 12 +8371 47012 10 +51063 51452 10 +7651 7194 10 +25559 49268 6 +6410 39539 8 +31195 42165 9 +46664 9030 5 +42386 30223 6 +48521 35241 9 +11413 19084 10 +8108 52099 2 +11172 34084 0 +19880 43420 7 +41486 16252 13 +23169 46144 5 +34720 11043 6 +38578 57561 14 +45831 30121 12 +58907 55995 8 +21139 20881 10 +34751 56026 15 +53053 42133 6 +55800 35302 5 +51748 384 9 +50347 44489 17 +55721 28133 1 +14018 4785 11 +52221 739 6 +20527 45365 7 +27329 54494 8 +16966 1368 7 +38160 29482 8 +15332 55622 3 +9044 21407 11 +16801 7912 10 +19078 46102 10 +17383 4398 9 +29334 6687 5 +16707 33915 6 +12441 986 7 +34611 6747 5 +56679 36606 16 +29468 40847 2 +11885 12607 17 +1004 43437 10 +49562 30897 12 +49835 19883 3 +35990 28437 8 +28192 6957 17 +34754 7532 2 +33456 47200 2 +11168 18655 13 +13860 51057 6 +56882 11944 8 +24692 412 11 +34043 38875 10 +25514 23980 8 +47662 28830 15 +52155 46831 13 +27511 32799 12 +29521 46036 5 +47605 40854 12 +8773 36645 6 +19449 46869 11 +41898 21334 2 +26569 34994 12 +42397 34203 11 +3980 6716 6 +19195 29148 3 +32467 26885 17 +42469 58946 6 +9669 43222 14 +50431 34267 10 +38652 14053 9 +19261 16346 6 +50287 17184 3 +25899 54322 4 +12779 11861 8 +3756 20340 4 +42992 59401 10 +17797 27134 6 +53057 15448 12 +2601 5933 3 +47604 21340 11 +1779 29712 11 +31529 43143 8 +42317 25097 13 +2854 53090 8 +16459 16639 12 +54827 51865 9 +43976 19014 3 +12113 52120 2 +35918 26461 8 +16857 14174 4 +7201 51167 9 +3318 36442 4 +55082 57814 12 +32937 29105 8 +25802 55589 5 +43133 33346 6 +14509 57043 5 +42965 30746 2 +4412 34582 1 +2288 36160 6 +57069 40856 9 +26325 26958 8 +25727 40117 14 +23408 46213 9 +5393 53818 6 +27800 53277 10 +1323 43796 13 +20919 54767 11 +51203 44180 15 +2615 2402 2 +12458 56434 7 +7565 7872 15 +14412 41651 2 +652 8325 9 +10210 12789 12 +26833 11126 13 +8136 41440 12 +59124 26535 8 +28878 9874 1 +44291 28789 13 +35603 45775 18 +36876 26220 16 +47262 31233 9 +19099 6129 9 +28653 20918 12 +32669 26294 12 +40703 43371 6 +42471 9480 5 +55737 2039 4 +28272 52210 5 +50159 44885 10 +9508 58095 9 +52437 58195 12 +16542 51790 7 +3108 59092 6 +51286 53179 6 +15881 33743 11 +7990 55619 14 +29807 28555 3 +39740 52131 5 +44755 2018 13 +9300 45273 6 +54480 3955 3 +22382 57188 12 +41251 40366 11 +33883 42406 9 +21794 59539 3 +22725 23982 11 +15425 4987 12 +43446 46310 7 +7695 20993 4 +48716 29763 3 +8844 10951 11 +18988 50658 7 +40122 27258 2 +24555 43905 2 +11586 14876 10 +30554 18064 4 +54513 7237 3 +11512 10075 6 +7291 17078 8 +12989 51749 10 +30487 45861 3 +10267 20365 2 +49603 6892 4 +28414 14549 5 +42000 20059 5 +46201 55363 14 +51853 31933 6 +25741 59452 8 +47191 20537 6 +38989 43894 11 +45738 16964 16 +9331 12868 10 +58028 38256 10 +26435 23200 9 +22029 12327 7 +25672 23183 7 +8206 18126 14 +13630 44832 8 +22078 25098 15 +32116 6048 11 +59579 54610 8 +31034 4665 13 +40031 55296 17 +38396 44328 11 +57244 51462 11 +16505 23381 14 +2053 51170 6 +51768 44882 12 +6991 54471 8 +25852 56135 18 +20561 19845 3 +13590 45801 4 +3830 43317 4 +51215 9525 1 +45172 25019 13 +30334 28365 9 +51226 12866 6 +10027 26922 3 +20447 25355 11 +27563 24312 16 +51677 16183 6 +48204 14765 11 +22624 36417 8 +43150 23975 6 +39609 28912 14 +55531 21360 10 +6597 3783 11 +12728 23805 14 +59831 2678 10 +16585 50917 4 +42747 44908 12 +48996 11974 9 +11179 13332 8 +32094 732 6 +18598 45632 18 +16558 15277 6 +18584 47157 6 +51893 57405 11 +46939 13834 11 +47247 19374 5 +39666 1325 10 +42271 56681 11 +13116 9378 10 +50559 41448 7 +45491 6646 10 +5606 21328 8 +46365 31605 14 +33590 31375 4 +37908 14086 7 +57579 57404 9 +27577 25786 8 +25467 59139 10 +42728 11726 17 +15824 18552 16 +23319 9942 3 +21565 6477 14 +47486 4231 12 +16915 4292 11 +33704 2182 11 +31535 52244 1 +15046 49663 9 +33653 47800 16 +43834 14825 3 +53307 15704 4 +19263 21344 12 +16640 51864 8 +27686 46604 4 +35496 15651 4 +8092 11130 8 +26472 40275 14 +5157 23217 14 +30257 56845 15 +32510 28954 4 +48937 34114 9 +22460 20950 7 +14507 42026 6 +55522 22424 10 +12240 36712 9 +58929 7361 8 +15687 36491 12 +15836 49442 11 +35969 4193 4 +3655 12551 5 +29099 257 11 +8197 3547 12 +32761 59861 12 +12349 52597 3 +14976 13614 10 +24170 33861 6 +36901 42107 10 +21700 19080 7 +53643 58421 10 +59008 29390 15 +36360 9730 12 +1949 49757 11 +27924 26692 4 +4252 57138 10 +4915 58320 3 +4242 49492 16 +25937 29805 1 +38734 50656 12 +37090 59841 13 +13555 50811 13 +56872 43009 12 +36165 55641 5 +201 56302 5 +44988 26410 7 +21607 49985 6 +7331 25434 8 +54129 15627 10 +54307 47069 9 +26255 1793 15 +10889 59296 8 +4774 5174 8 +43732 8749 6 +1366 17730 10 +25114 9136 5 +54316 8549 11 +33958 55006 4 +35715 39982 12 +41662 56031 6 +8938 54260 10 +3378 17191 6 +58019 24326 5 +3698 55513 5 +37855 41234 5 +18222 43777 9 +47135 2748 2 +13194 3785 18 +19160 10687 7 +6231 37658 5 +3397 11388 12 +35260 2736 7 +44103 46985 9 +23863 9163 14 +46193 8128 14 +19869 56007 8 +1218 59048 10 +33960 44757 13 +57756 26598 7 +54576 10559 9 +50219 41523 6 +13132 6065 4 +43687 59914 11 +6596 29250 4 +45005 47416 10 +3634 9931 9 +20859 17408 14 +41552 43315 4 +17471 48811 5 +11917 6330 1 +9222 40491 6 +40535 58616 14 +21955 19471 12 +25213 366 9 +38040 39227 11 +33800 57396 4 +39764 9012 9 +41859 39455 7 +7471 37050 6 +27629 58867 5 +38131 8605 7 +4234 50996 11 +20454 56085 10 +52169 34805 5 +37386 19012 2 +53252 19393 12 +15019 20053 11 +5959 9220 15 +10240 49102 4 +31490 12971 1 +14773 48370 6 +15938 8277 5 +22042 40190 6 +35133 5036 8 +21771 12494 9 +1732 55309 16 +2794 17657 7 +21679 43397 12 +42131 35467 8 +36929 32820 7 +13406 59696 2 +48753 37085 11 +6801 42054 11 +6403 23261 13 +19664 57656 6 +37974 28115 8 +56395 21423 13 +45984 26582 10 +25742 5652 13 +57276 16768 14 +7379 49579 14 +14328 15081 13 +58979 59122 11 +45236 26312 11 +31385 2719 8 +27653 43958 14 +29998 32480 15 +19705 7503 14 +40011 17622 17 +4465 8597 3 +16530 14415 7 +18715 42508 3 +33040 43555 13 +22126 33962 6 +11500 31526 6 +27049 625 10 +54440 25260 6 +10067 52041 4 +10589 12404 7 +42559 52356 9 +44559 51353 16 +12572 37264 9 +31829 10120 1 +40910 8624 9 +49660 50277 16 +38066 2912 8 +12532 46849 3 +30618 31161 9 +13361 57203 10 +28245 6446 1 +38219 43195 6 +26898 42973 11 +51574 37031 14 +2689 45490 9 +12966 45291 10 +27663 50758 9 +24351 43245 12 +29330 27417 11 +10168 10735 7 +2973 59638 16 +454 4146 5 +5780 20010 6 +38934 32110 13 +5509 1929 7 +11751 40438 9 +1738 53000 9 +1763 26706 9 +13773 42323 5 +3789 50939 11 +29281 34048 12 +54453 55597 11 +9474 14959 1 +8996 51269 10 +39790 53621 8 +8710 22493 6 +36449 52245 3 +6472 14332 14 +47903 55258 12 +48921 24622 11 +5696 29238 15 +31888 28337 16 +46178 31777 5 +12029 48632 15 +48526 7115 8 +4118 3575 14 +15572 56378 11 +36383 19009 6 +35212 49389 1 +28928 33169 12 +37452 12531 9 +45010 12466 14 +3163 27229 10 +36641 28962 12 +34989 895 3 +33051 50605 11 +20600 50554 10 +52798 19663 12 +54224 39432 14 +480 1959 8 +13425 49997 17 +40173 11227 4 +29158 32982 11 +15793 49995 8 +7929 17818 10 +59499 19930 2 +5457 10724 13 +55093 56278 4 +58501 39334 1 +15245 305 10 +3963 19132 3 +21343 45840 0 +451 33359 4 +37877 42374 9 +22887 3566 14 +36413 7665 16 +49053 27177 15 +34880 27385 9 +46583 44219 8 +37497 39801 0 +17279 8545 1 +7217 17029 10 +30624 54747 8 +13637 1239 15 +22797 10968 13 +49514 55421 8 +6007 3483 12 +17288 11951 6 +26004 10959 9 +55697 20604 9 +21067 23235 14 +18413 6924 10 +58651 21322 9 +43899 19571 8 +116 49069 16 +22347 5793 4 +53009 27369 12 +23880 25032 12 +49755 54976 10 +53876 50213 5 +7040 57732 10 +58583 33464 7 +24611 2873 6 +26941 18333 9 +8555 24587 17 +9552 38926 0 +22927 10069 9 +53542 3241 3 +1849 20260 13 +30270 51124 6 +22972 7977 10 +28042 32700 15 +56511 6744 9 +54027 58154 6 +36051 44478 5 +45766 23473 1 +47497 1633 10 +19321 40004 3 +32036 36737 0 +42228 32020 13 +38243 23378 7 +41172 48424 11 +11042 46206 12 +20040 19728 13 +41781 54128 5 +57984 1620 17 +33380 35644 11 +31125 53655 11 +25062 59885 13 +25093 30095 13 +27282 156 3 +14318 35941 14 +50690 16968 14 +7718 52769 11 +49467 54688 10 +40223 4346 7 +32207 34234 4 +28316 35612 3 +46531 19465 8 +52713 34714 3 +38741 5887 11 +35428 11968 9 +32310 59168 7 +23167 423 10 +5521 11072 8 +1161 30591 12 +6195 48601 5 +47462 3027 16 +52163 24884 13 +54951 14164 11 +49792 25308 9 +4316 13883 7 +10437 47865 13 +40803 15569 2 +6693 46844 12 +58098 121 2 +10522 12325 7 +16275 34070 8 +18699 884 12 +45284 27684 2 +20619 54303 7 +43714 19942 6 +25461 14664 8 +18015 14828 14 +55749 34668 11 +54816 44051 4 +14122 29343 10 +145 27102 9 +6345 54152 16 +12567 39502 11 +14245 36612 14 +9718 49207 7 +53518 8939 3 +34423 15551 5 +48215 46894 8 +8504 55893 8 +40425 32508 4 +48026 49957 5 +8365 10950 14 +31367 14856 3 +23909 12118 15 +21749 37828 6 +11209 19920 9 +13925 28705 6 +36705 16916 5 +43314 23276 6 +51513 52317 9 +23247 31476 6 +9948 48775 17 +26748 42089 15 +56323 16416 17 +32505 42243 4 +31710 57682 8 +13253 24843 14 +20813 13175 4 +46642 14548 10 +45909 51469 4 +47857 25605 12 +21244 8712 10 +38879 52101 5 +43781 21764 10 +9043 18055 1 +7244 23520 7 +22588 53824 8 +31877 30716 6 +52824 12931 9 +13747 7859 7 +46999 7747 6 +11417 49979 9 +36682 27588 5 +27374 42475 8 +34520 15575 7 +5313 44745 5 +21350 42745 6 +39480 58459 10 +27851 15375 11 +17291 53657 8 +11365 41136 11 +36122 54475 9 +46736 2545 9 +58177 51676 13 +23979 42236 8 +34780 5052 4 +30424 6030 8 +30602 59631 7 +17183 50667 8 +42008 36925 7 +39719 51444 7 +53052 36078 7 +40485 44252 16 +46638 51471 10 +4436 50905 11 +6280 1457 15 +57483 36990 12 +35823 11590 5 +9419 29285 6 +24104 29646 5 +25469 17284 13 +1089 4625 10 +35773 13676 10 +8367 55499 7 +53867 50738 12 +24003 41728 7 +48007 12237 17 +30406 55299 10 +23403 23216 4 +39140 14046 10 +56282 53242 9 +8479 21329 10 +49411 8974 8 +31623 40439 15 +9523 47056 9 +25425 23638 12 +37797 18751 7 +3604 21482 8 +58103 8800 5 +55835 16161 15 +4345 16352 9 +7153 43902 5 +37409 11290 12 +24767 37196 5 +7083 53424 4 +29470 52758 8 +26542 18345 7 +38319 41365 9 +17990 271 12 +37938 26207 5 +58358 29927 9 +39142 36254 14 +29898 31477 11 +21010 16528 8 +1865 43258 4 +46881 42186 7 +9338 39885 9 +45871 19093 8 +45494 18281 8 +5399 52799 3 +54251 31090 13 +18398 15150 4 +5025 52693 8 +30159 30973 10 +20194 34588 2 +29487 830 7 +47922 1203 6 +14578 59365 6 +38431 26977 12 +12956 48604 7 +56370 38532 6 +14334 31628 0 +36600 45339 6 +36545 13119 14 +13101 20342 11 +53055 13568 12 +44654 16617 17 +44043 49585 12 +57124 32131 5 +10289 4557 7 +18241 47431 13 +57871 39839 2 +25397 6354 9 +54737 3099 11 +5843 47256 7 +48666 39093 3 +8289 11572 5 +31135 11223 17 +32085 56818 5 +5 31511 3 +4818 41160 12 +42838 55440 12 +20476 24387 14 +4076 25897 12 +1112 34005 14 +31012 8572 8 +24769 6663 8 +48588 46059 12 +27073 11 7 +18012 10024 10 +599 11211 15 +40798 20673 9 +48228 4046 14 +48399 45390 9 +59801 22953 12 +37959 37839 4 +21278 42891 5 +282 8680 17 +30800 26630 2 +49648 25522 10 +49971 6415 3 +1646 38462 5 +19200 43677 6 +56512 48640 2 +12974 779 9 +33176 12693 2 +7468 54124 15 +26169 46623 11 +41916 10234 8 +8356 39676 16 +50209 9473 9 +57127 31438 8 +2619 9990 8 +2187 7114 12 +15785 47548 11 +22491 3302 11 +44650 10093 4 +49296 29192 14 +49695 8084 7 +10922 42350 7 +57471 27062 5 +1230 24377 7 +42251 28252 6 +56464 57426 12 +3559 44565 8 +9890 19142 6 +57181 12435 9 +51919 40038 9 +7810 7071 17 +17822 21919 9 +26980 38327 6 +14623 53 9 +42837 9008 9 +1469 9121 4 +2852 45343 16 +13741 12448 8 +27973 22906 11 +55748 50673 9 +16192 17667 8 +53072 37853 9 +44549 9727 4 +35052 12900 10 +17921 21509 18 +43653 1837 1 +19212 53567 14 +35162 249 3 +23143 2475 16 +17705 4421 15 +10767 42617 14 +2109 46360 5 +6122 55029 1 +58072 22201 9 +27485 13654 9 +56630 56365 6 +30438 38190 6 +12445 153 11 +35992 25402 7 +38147 36317 5 +10000 15421 8 +44225 44440 3 +42732 41716 4 +16734 46095 16 +19363 46334 7 +1064 5219 17 +6541 57243 7 +54114 20048 14 +5640 13535 5 +17398 55802 16 +6311 9493 5 +48893 52792 12 +33116 34078 8 +55123 5149 7 +36312 6675 7 +36128 26511 9 +51156 11932 15 +11404 45955 2 +30175 5388 6 +31912 7376 15 +53083 27885 4 +49560 25555 7 +48362 10938 6 +54534 38645 7 +45502 55138 7 +23016 49017 13 +10653 52119 6 +11225 11741 17 +31180 35303 1 +31728 16090 13 +32753 41707 10 +44409 27044 11 +18979 18837 7 +12560 3853 4 +6259 21413 7 +20929 8410 6 +28768 55198 9 +30668 47093 8 +48541 46619 7 +40138 2203 11 +29513 57021 17 +3535 14343 7 +11319 27441 7 +53129 16399 11 +28847 17123 8 +43419 27009 14 +34500 2533 14 +14366 11755 4 +12125 21130 8 +37086 11690 9 +55240 47264 18 +29323 3337 1 +21375 32853 15 +58662 35464 10 +8881 59191 15 +2218 48804 9 +14352 1529 6 +5718 40699 11 +33010 9548 13 +44329 24724 7 +50552 31142 17 +26467 4510 8 +42948 37094 14 +27562 57241 8 +8927 1400 12 +35401 35666 12 +57153 28538 11 +45918 14863 11 +48019 12719 10 +47808 10913 12 +38699 9083 6 +8683 49787 7 +50383 26412 8 +39039 9475 6 +20684 2546 13 +6575 38345 6 +40033 41579 3 +12813 46515 14 +38174 57201 3 +25858 42078 5 +23940 59088 7 +20645 23514 5 +12266 33616 7 +55141 43910 5 +5376 7974 12 +49089 17847 3 +16942 27798 12 +1969 13895 8 +4395 27443 10 +48969 33992 8 +42908 5395 4 +50661 51558 8 +23080 10040 3 +44301 14185 8 +56484 45572 5 +46970 42276 10 +16126 8166 6 +48425 21946 8 +20314 7238 8 +33972 36875 7 +57106 27595 11 +54628 21462 11 +34224 50774 9 +42114 46798 7 +27616 17246 10 +8625 22195 10 +42175 12708 10 +30102 12624 9 +42783 10523 0 +10138 53044 11 +59880 33875 8 +24847 8321 14 +2244 31048 8 +57421 28908 18 +51689 137 12 +40151 13878 6 +8209 22430 5 +50717 37896 6 +10784 27146 17 +49707 52815 8 +52290 7296 12 +5361 23544 9 +22912 38594 5 +54810 27408 5 +26319 53001 5 +26505 13816 3 +48852 1314 14 +28539 29173 9 +22548 22769 4 +43111 31396 12 +10102 15499 16 +48633 18249 12 +58788 49765 13 +49701 33534 8 +30449 12148 10 +23193 36883 13 +50755 13847 10 +37707 11633 15 +22045 44326 1 +22635 54848 4 +35109 59589 5 +52740 48477 12 +42663 16886 9 +59264 32039 12 +29504 42377 7 +30225 35483 3 +46867 4859 10 +18176 18130 9 +54304 48069 8 +49112 45120 18 +9731 30578 9 +9326 45074 14 +15947 52599 3 +17966 47386 3 +59788 657 4 +5889 50596 14 +37209 18074 4 +26486 6412 14 +12054 47188 16 +26066 48830 5 +15173 47700 14 +25151 685 9 +21477 37103 3 +20773 5935 15 +12081 25224 16 +14301 5814 9 +44744 5301 1 +18885 51119 11 +2776 26224 3 +29324 52406 16 +59519 40952 7 +46427 35511 6 +51625 15108 4 +42680 12109 8 +40719 5035 11 +17263 25343 11 +10962 40395 8 +53012 32188 5 +55831 56495 6 +52007 15642 6 +23398 16575 14 +11297 27035 1 +1081 55292 4 +39939 54531 5 +5490 5227 6 +325 15000 7 +55839 51498 10 +49084 11491 8 +25548 28517 6 +47879 35550 10 +52970 14713 10 +53599 8787 5 +51275 11574 2 +6207 52787 7 +6366 16189 8 +2213 56998 9 +47325 38014 15 +38955 11406 11 +1129 24859 7 +48279 58176 8 +5302 43061 13 +31949 29074 3 +6320 13307 1 +14095 8194 8 +27276 37153 1 +48925 29902 9 +16506 25394 7 +13320 57378 9 +50962 26234 9 +5534 21112 11 +2664 23961 4 +35935 11416 15 +44245 23621 8 +53462 46200 16 +31394 7427 9 +19675 5099 9 +44715 14577 9 +47481 51455 12 +7272 4500 0 +8966 7793 10 +39434 13750 5 +8748 42288 6 +8241 24154 7 +8156 42422 2 +53632 35757 0 +2494 38027 7 +35405 37505 6 +59997 26166 9 +27707 6830 6 +33994 48612 4 +53618 34988 8 +37426 21385 7 +7234 34174 7 +8421 30943 5 +23300 21331 14 +5141 34381 6 +40539 22166 10 +26206 53937 5 +26544 36151 8 +51951 38599 4 +57340 14460 8 +48536 30930 8 +50166 55796 8 +52035 40436 10 +3126 56194 13 +7451 39044 0 +28451 33948 9 +39026 33494 12 +25125 34888 12 +42985 47202 0 +10205 38823 2 +28439 57644 2 +33799 30392 7 +29199 26182 1 +29710 51686 12 +15094 3284 11 +48294 43647 10 +13382 44142 10 +56397 58514 4 +11892 13438 9 +55246 34317 7 +47712 40784 16 +9495 34802 8 +38896 1901 13 +34535 35622 9 +23715 9489 9 +5813 14967 5 +11199 36065 14 +11771 41720 10 +53442 52211 13 +17126 32361 8 +40787 29344 13 +26700 52546 14 +24076 38210 11 +32158 47575 3 +21250 24450 5 +43234 52457 12 +51862 25376 16 +526 15829 2 +10529 56586 14 +51968 49902 9 +1659 45344 14 +41386 1011 3 +20380 10510 14 +17213 47033 5 +52878 2712 10 +47539 40925 6 +42032 47401 12 +58005 46136 8 +57855 4407 2 +52664 36784 9 +58580 14858 2 +30014 46169 7 +9757 39440 8 +33794 46415 10 +36604 786 10 +36980 36221 14 +33135 44385 9 +59894 42872 15 +9686 5715 10 +37957 29758 8 +49087 57889 3 +44847 46006 3 +10144 38588 11 +10932 10656 12 +54875 30097 1 +24994 14921 13 +11397 9014 13 +21450 619 4 +58338 49827 15 +17278 28240 16 +18596 7576 6 +13545 39447 9 +37771 38689 13 +24151 23699 6 +39752 15567 7 +6600 34998 14 +16935 43533 14 +24011 31558 7 +31658 27168 9 +19655 33968 8 +40012 28342 16 +59634 26499 16 +33995 45457 14 +21867 40006 13 +40530 27716 9 +57543 23510 8 +30613 18830 5 +17463 53246 12 +24305 35423 9 +2681 22929 8 +38377 53857 3 +5686 30759 13 +55778 5708 10 +35691 33259 3 +4883 41756 3 +14816 39718 18 +28446 1476 12 +18437 18462 9 +25176 38238 7 +15009 19669 1 +27656 24590 9 +47563 51719 10 +37982 17094 11 +11325 33109 12 +21493 46553 4 +21064 24520 2 +14678 50927 17 +20951 21502 3 +46535 16392 1 +59489 2556 8 +22349 35403 3 +7171 25116 12 +32410 7668 10 +41177 42055 12 +22939 4733 8 +51765 30126 8 +2563 38555 7 +26008 19458 11 +45446 20508 16 +36154 52448 7 +48202 21255 6 +58006 28731 11 +14605 53191 15 +51775 44163 13 +54574 7824 10 +12684 30389 6 +4635 18874 15 +19647 19709 6 +26791 34705 9 +42938 56781 3 +52821 31615 5 +24254 8072 13 +58840 9598 11 +28107 57974 6 +5389 15299 12 +27301 17788 7 +20700 26210 9 +58674 47055 9 +214 20295 14 +9616 31951 5 +36445 10491 12 +55042 20575 10 +24572 40770 8 +34187 38560 7 +7181 46223 8 +22779 2749 7 +10581 44111 8 +38545 38165 6 +57957 19345 3 +22479 52436 11 +32839 51771 9 +19248 59896 4 +17918 41542 8 +47577 28411 9 +30031 7355 1 +12854 49784 7 +29229 53988 12 +26072 38133 8 +56269 58172 7 +1974 28672 10 +12279 50315 6 +3735 37694 10 +54591 20052 7 +11463 49730 13 +27569 43404 1 +32179 54695 8 +3586 15597 13 +1055 16184 11 +36368 5051 2 +13451 54182 5 +44439 43054 9 +28760 11763 10 +2094 23503 3 +4544 57147 15 +33220 21598 7 +27056 34979 12 +48542 27413 2 +32649 3277 16 +35476 44733 12 +20057 26613 8 +13232 10520 8 +25270 17269 8 +11098 36274 12 +15383 24582 2 +788 46861 15 +52037 51776 11 +44500 29806 14 +20179 56925 5 +58637 27901 13 +14325 41244 7 +39037 23470 1 +39731 49400 16 +41002 3653 16 +33778 15789 9 +43012 43191 5 +57917 25874 9 +37576 56390 13 +32071 44798 7 +59419 55178 5 +6788 40187 12 +4129 34869 2 +43996 35113 5 +48360 26996 11 +46632 22584 10 +42516 30687 15 +24656 9622 7 +43339 46350 4 +46245 48369 9 +34274 33601 11 +2484 45650 5 +55567 13746 8 +53726 10618 5 +5316 36106 10 +23304 52504 9 +55700 14077 16 +43599 54993 12 +4757 30764 11 +10506 33209 11 +10969 18961 11 +25964 29726 9 +7021 34456 14 +22004 27297 2 +56493 46434 3 +59283 1998 6 +2507 32954 13 +19122 26115 9 +32174 24091 13 +34634 49658 5 +50903 37675 13 +25573 18393 4 +51697 34049 12 +40728 49289 11 +14841 28564 16 +10821 26261 0 +44928 35384 14 +16371 33192 1 +52115 26383 11 +54264 58047 8 +52365 36406 9 +806 52550 11 +23831 37976 17 +44071 25281 11 +3354 59828 11 +6456 20998 12 +50273 21911 3 +52337 12997 11 +38229 5421 6 +29427 46573 11 +54340 34319 9 +21622 15855 8 +2666 31481 13 +30792 9614 13 +40296 34249 12 +697 41326 13 +4920 44846 1 +36924 55247 10 +23865 10927 16 +12182 3841 14 +38877 19604 9 +47516 51848 4 +14026 14953 4 +4249 6450 9 +39635 639 4 +37897 7485 1 +2561 22112 2 +6092 46106 16 +18576 33636 14 +29724 5963 10 +17395 22977 9 +55368 22532 16 +54623 19351 15 +47571 33611 12 +3964 48257 9 +57470 36650 12 +20262 42416 11 +40356 44930 11 +23927 55703 11 +41903 22218 12 +10145 31729 2 +57036 45077 8 +25518 8111 9 +50707 13655 16 +26877 2889 10 +56759 13547 2 +8774 13882 7 +30997 9009 7 +1799 40267 7 +7192 26400 12 +43787 31751 9 +20134 35122 10 +18563 18041 8 +8571 22413 10 +13168 6080 3 +36583 21617 13 +3119 36750 13 +28886 45952 5 +43072 23457 10 +38419 45050 17 +21076 40498 6 +7946 26545 9 +24937 42991 10 +38430 38299 8 +15928 2653 7 +45795 47189 3 +6447 1335 10 +29254 51788 14 +44085 34673 16 +30794 19131 10 +57122 43744 12 +23569 16309 8 +14776 13958 7 +5102 6847 3 +32579 42672 9 +14913 30247 16 +31931 37899 10 +18452 46630 8 +46260 51656 15 +7699 32933 8 +5770 45408 6 +7050 10314 3 +15801 24468 16 +35819 55327 7 +57800 45569 14 +45211 43792 14 +53840 28351 14 +10254 33898 8 +11828 4247 11 +52838 18551 8 +12723 39703 4 +42622 52622 3 +1100 12750 9 +6135 48962 5 +26500 38906 11 +5980 7505 12 +11792 2692 1 +6896 48469 13 +43206 50136 6 +56400 53852 11 +51560 40758 15 +1653 53357 7 +1010 12085 10 +46017 27609 0 +48070 36364 6 +33913 16946 8 +41638 7219 1 +22688 32502 10 +30404 37033 7 +204 119 6 +39212 52644 13 +20803 4518 3 +15521 33406 11 +49426 20392 6 +57836 20679 9 +57867 44431 8 +34313 3243 16 +29090 49657 8 +22604 59674 12 +35893 38472 15 +10480 12964 15 +45282 57886 8 +45271 58386 3 +31700 59479 11 +29400 4057 14 +5787 20039 10 +52732 44221 15 +10454 41308 9 +38591 54542 8 +31773 37751 8 +45198 17810 7 +58654 25043 11 +56482 54877 9 +41816 42507 5 +44224 9722 6 +34876 36899 12 +58119 53183 12 +44088 2716 5 +44223 42547 13 +47986 27717 8 +58310 39859 7 +52830 8849 15 +28715 42410 16 +45102 22174 16 +9116 59278 9 +31855 11986 4 +10442 24494 15 +46112 22141 12 +50461 56356 14 +33729 49885 8 +55428 45354 5 +42986 43455 9 +6192 25970 2 +10582 3272 3 +10761 26493 14 +11887 28630 2 +7278 3502 15 +45814 26917 10 +13791 26549 16 +54011 44289 15 +5130 17617 16 +55497 6985 9 +49056 52909 11 +50901 12162 11 +30832 6275 10 +32392 29019 3 +55390 24639 13 +40850 41390 5 +2525 47741 5 +40522 42785 15 +48995 59251 9 +15454 58091 1 +39499 29469 8 +34658 16742 7 +54509 31425 9 +24699 36141 8 +15737 24422 15 +36707 53816 4 +20790 36511 6 +13082 32182 6 +30603 49244 9 +59753 24280 11 +59074 35488 1 +18285 11226 9 +30484 27751 1 +9714 25945 5 +45516 30039 5 +20531 18785 3 +15179 55952 6 +18133 44128 10 +46744 37225 8 +21336 29525 14 +22617 59431 14 +6255 18411 6 +57783 35458 9 +59826 51086 7 +12508 43218 6 +45060 50233 14 +20870 51906 9 +41249 21953 1 +44368 36919 1 +32563 18474 4 +28516 15624 9 +16315 13828 11 +43046 39404 11 +30861 44900 4 +37553 28373 13 +55505 28336 3 +27254 25172 10 +47147 21234 12 +678 47446 2 +17162 41442 14 +52931 11567 7 +58542 57926 14 +49189 21215 2 +22014 28251 9 +2954 47521 10 +2324 59373 7 +2327 48961 4 +52394 23 4 +34550 16619 4 +22240 14560 7 +39799 56241 5 +47954 26602 13 +39435 2354 6 +18849 50024 6 +17505 17556 7 +12686 33833 4 +53710 13317 7 +3641 26817 9 +38191 17411 7 +34849 23892 2 +21785 12241 9 +35022 41831 11 +56784 24016 10 +26148 3928 11 +35297 36692 6 +45454 28772 8 +5932 9654 9 +21533 8293 2 +39465 14844 10 +14490 186 8 +57748 21605 13 +59040 39378 10 +26593 42045 3 +51921 26840 4 +4746 57230 11 +31599 58125 15 +28096 12962 9 +17649 8416 16 +9590 35623 10 +49531 37046 16 +34653 18072 1 +19383 12832 16 +4917 2808 7 +989 34255 8 +12595 56239 4 +9015 53910 8 +19659 8082 7 +33279 6272 10 +12498 11033 5 +44723 39187 8 +31869 30742 2 +6613 16450 5 +45415 42367 18 +57770 36144 12 +37904 33044 7 +48371 37685 8 +22897 10734 3 +10838 25909 10 +42525 44411 6 +15355 52488 10 +52016 192 2 +49078 19390 9 +55286 13993 4 +51420 41471 10 +237 44257 11 +32953 42125 7 +8098 3608 4 +58900 31455 11 +34386 11913 11 +34432 56736 8 +22441 45222 5 +10023 19716 17 +14567 58269 7 +5285 714 2 +7722 3281 12 +46461 21412 8 +39825 11546 14 +3948 10242 7 +24758 19193 11 +16773 19957 12 +57521 39336 7 +34763 58639 17 +53574 19197 14 +4535 52005 6 +3414 55370 18 +41647 43266 0 +22514 41227 18 +11997 30589 4 +35896 18350 9 +44841 56144 8 +19213 56850 9 +22062 49475 4 +12079 28264 5 +58434 43333 9 +49982 27733 12 +31913 59597 5 +17453 747 6 +35015 9265 12 +19042 8511 16 +10596 49237 12 +18857 51920 13 +26267 4676 4 +49770 15416 4 +8069 38953 9 +19244 55540 11 +2149 29826 10 +59164 4440 17 +3680 33661 2 +49323 46020 17 +48739 57739 11 +11603 46993 13 +17545 48629 9 +35192 42644 1 +6304 4425 16 +45503 636 7 +30199 49246 7 +40983 1907 1 +54903 35208 7 +11697 47265 12 +3453 15853 7 +38476 32784 16 +58286 11285 4 +55405 43922 11 +18833 8716 4 +49420 53953 9 +14154 11138 4 +54526 31157 6 +13098 28861 3 +9529 29845 8 +8791 50571 15 +4928 21158 16 +22402 11787 10 +35194 36468 9 +12048 54431 11 +36522 49932 3 +52296 17596 16 +18942 41372 2 +35772 12087 13 +33094 23614 3 +22774 50429 12 +50990 40424 4 +16350 14378 11 +26356 57659 7 +4889 42578 1 +19203 15903 1 +52152 35092 4 +30332 59043 6 +50598 4321 6 +39479 22933 12 +50652 44639 3 +39078 31618 9 +56655 56601 9 +46367 44769 13 +12622 54857 10 +59877 36789 6 +57379 57008 17 +19993 45104 12 +48278 31921 11 +17131 26757 4 +27593 41153 13 +20061 20020 15 +1027 11753 17 +33375 36856 16 +1662 55553 9 +45948 56410 15 +34096 10664 1 +15064 59939 9 +52261 39410 12 +22784 4754 17 +55237 58027 13 +13589 29183 8 +45825 21138 11 +28735 56652 10 +18431 52570 14 +31447 1191 8 +55726 9198 10 +11034 6561 6 +33295 36185 2 +4155 46114 6 +26584 26390 7 +50237 19318 6 +38370 8291 5 +17880 56024 7 +38063 7216 13 +48595 39586 11 +43449 49280 2 +4239 37968 0 +8163 11889 8 +33473 29164 12 +9501 43614 12 +28857 56169 2 +30944 18664 10 +52240 57667 12 +39017 37519 5 +37568 33979 10 +43975 43514 4 +21090 34443 3 +32984 31982 8 +30616 20049 1 +29213 12969 13 +55907 43942 3 +22409 38819 11 +58748 45672 10 +31929 42081 5 +32154 42484 9 +19580 22336 14 +42734 16074 5 +7250 3141 8 +56155 46147 12 +44510 2753 7 +7869 38946 7 +48888 55190 12 +18253 16799 9 +33567 113 2 +44012 43474 4 +23229 57031 10 +10884 44032 8 +14635 29982 10 +14091 27668 7 +11693 29510 5 +43424 22772 15 +39868 25324 8 +41 22537 12 +10213 34016 6 +6523 37360 10 +18124 19299 4 +37431 31591 16 +51034 47374 14 +7596 34015 8 +43069 18844 15 +23642 26076 9 +58298 40586 3 +33701 52556 18 +9385 26888 6 +45911 6993 12 +1638 43650 14 +13968 21852 6 +8260 9397 10 +3138 59608 8 +31926 37265 14 +54982 49106 2 +43152 34825 11 +40207 34943 5 +23441 22788 3 +17444 19442 7 +35863 39867 11 +33119 57446 6 +52453 31295 11 +52100 18632 8 +10862 25972 15 +30707 57322 1 +268 56015 8 +36149 18571 7 +13485 19364 13 +58634 43738 13 +41954 33841 2 +27476 40840 9 +44530 55945 11 +13077 48643 2 +47830 11539 4 +20787 10173 6 +26705 43228 11 +35912 37829 7 +25889 47060 11 +18166 30090 12 +31733 53032 13 +46420 47824 12 +10303 720 12 +6625 50671 12 +29603 5747 1 +17933 8922 8 +21127 34262 1 +24500 57979 8 +53429 36464 9 +46950 33602 12 +34208 23288 11 +5167 58214 7 +56706 29473 11 +12598 43170 2 +17312 14827 14 +3421 35809 14 +12453 37663 7 +24299 43183 12 +44448 44737 7 +53708 44255 8 +2336 13711 2 +3443 31919 9 +20426 52255 8 +48079 44078 7 +7874 39570 0 +2231 42860 17 +48652 13944 16 +56859 59396 11 +667 10890 7 +43116 48504 11 +30441 33557 9 +42647 26709 13 +44536 28084 13 +29736 13100 2 +28106 41325 14 +35203 50099 16 +16544 58033 3 +26296 30353 6 +56360 32041 6 +19137 45956 16 +24271 52181 10 +12335 59112 9 +16909 10573 9 +56254 34231 15 +35910 34415 13 +52144 8796 6 +20469 47518 10 +41881 15710 3 +5737 12331 10 +47878 4469 11 +13424 31822 17 +56848 30387 8 +38067 21828 12 +44553 8917 9 +34196 24189 9 +34731 26233 9 +19252 52134 7 +48351 6607 8 +13686 57271 11 +56639 14704 3 +8349 40723 4 +49729 30345 9 +14157 21848 0 +53224 33870 9 +15118 49586 8 +42927 46877 5 +38863 3702 8 +20163 39754 10 +10685 18701 14 +45875 12197 9 +52524 40868 12 +58026 36117 3 +38083 52368 4 +2877 55400 2 +22375 29133 1 +28558 29713 7 +22703 38748 17 +10797 57055 13 +8279 15715 5 +51173 24848 4 +40228 43682 6 +12213 46886 6 +35235 20533 2 +15057 40181 3 +23583 935 12 +59765 55313 18 +36828 15738 16 +59120 37159 9 +43939 44473 1 +17758 53099 17 +14107 27427 3 +6662 5045 12 +24851 2367 13 +7036 36426 5 +49047 7701 9 +29610 43097 11 +21927 50547 9 +25205 18987 9 +37199 18262 8 +5182 59974 9 +53340 24854 7 +45959 10056 8 +11191 56835 8 +54544 27228 6 +18673 5211 10 +38235 34002 6 +43271 9087 10 +37427 26772 3 +44094 36730 7 +59318 47126 12 +18968 37388 9 +6860 10598 7 +26707 9705 8 +23897 13056 10 +9779 49487 11 +31075 58546 8 +16885 22117 10 +30565 50549 5 +31796 53865 15 +19900 32315 1 +56937 47282 10 +16573 49340 7 +31128 23533 15 +40343 8955 12 +32983 11451 9 +56104 3155 3 +41559 37263 9 +59790 16730 13 +29731 40842 13 +53875 36574 9 +4159 22348 7 +15633 50989 4 +17579 28832 4 +43280 41041 3 +37152 37430 17 +6439 12592 12 +44394 26109 10 +29942 5345 6 +25780 26689 4 +55257 16108 5 +7220 53068 12 +50781 43541 13 +39538 9157 16 +22502 22437 10 +4982 5868 17 +21093 41666 11 +16606 9428 9 +41122 17561 4 +31584 47753 13 +952 2482 8 +36549 15270 2 +30106 19227 7 +8041 23912 9 +3213 50451 5 +51349 11562 5 +24335 22512 6 +7365 54830 15 +20394 49561 1 +42219 42429 4 +22238 44708 10 +8978 48123 6 +16379 42018 11 +45557 23666 7 +22535 32364 11 +982 24421 6 +44572 41749 11 +52951 37289 7 +51617 32004 10 +23248 17559 15 +5023 31256 10 +31342 12070 10 +18372 2683 9 +2161 20448 9 +52483 4863 15 +15389 43938 9 +29613 30055 5 +44888 41001 8 +39915 21935 12 +52318 8250 0 +11165 39369 10 +11220 20541 13 +15892 59620 9 +22186 31378 9 +25575 355 5 +58051 14574 1 +41982 37988 13 +51006 56688 1 +16334 51378 7 +54757 46426 15 +45377 17674 12 +18408 34538 7 +707 51018 13 +28262 9054 11 +6951 57062 9 +57009 12935 7 +43782 30433 10 +17059 447 7 +39761 25304 3 +45510 19825 11 +37615 29892 7 +48109 43352 9 +51830 12738 17 +37592 38631 9 +51885 46887 9 +41418 24881 3 +31227 37359 13 +52213 30120 7 +28788 2370 17 +21062 31537 8 +46484 35885 2 +59049 31383 15 +30940 46896 1 +1878 34758 17 +32411 46851 8 +10873 34470 8 +309 11234 4 +44822 38077 10 +34099 13497 0 +8575 56886 5 +16083 35607 6 +43032 56422 6 +59567 59532 15 +23867 32383 9 +19201 7024 13 +15857 55686 4 +24289 10076 7 +31332 58359 6 +26216 23693 8 +6705 43219 10 +54784 3371 10 +14013 36467 8 +44992 15547 12 +54753 59466 9 +56084 15059 8 +28242 42594 7 +6887 8637 11 +51785 9720 8 +53663 1092 14 +1749 2571 13 +45867 21726 5 +31200 51834 9 +20364 31843 9 +28024 27614 2 +17832 25662 7 +5982 11294 11 +41563 20344 12 +30168 30287 10 +35472 40993 9 +21258 23158 12 +52648 53264 3 +14074 1795 10 +45606 39717 8 +56809 24067 8 +21674 9414 7 +4445 45246 4 +42897 16079 14 +35183 7821 5 +32501 36950 7 +8935 31021 3 +53321 51520 1 +13913 49998 4 +2735 31654 9 +928 36746 13 +51097 6601 8 +16860 54548 17 +58853 44146 6 +10094 59133 14 +54061 49214 1 +55162 332 11 +30074 59203 6 +26283 26895 14 +3402 59313 3 +29568 54955 15 +16444 55383 12 +11200 44954 8 +9562 29626 3 +7465 21563 5 +51417 36767 8 +24877 18381 6 +36520 20688 1 +17883 4364 7 +16006 10232 18 +5394 17908 11 +16410 44357 15 +41763 49403 15 +55662 37838 4 +35544 44453 8 +10500 39508 7 +26926 45425 11 +15226 4071 5 +51008 14718 15 +13363 33803 8 +25359 26337 12 +37324 55416 12 +40753 59882 10 +56976 31789 10 +13016 39082 15 +21159 57798 7 +1894 34897 8 +8801 29382 14 +34679 25759 5 +49497 42151 6 +16044 57158 14 +49868 11779 3 +2937 16748 4 +25411 45149 7 +24319 33190 10 +27836 22247 2 +17615 19605 15 +58224 49977 12 +35836 52161 9 +43773 25754 3 +28791 9424 10 +2171 8941 5 +46218 20035 14 +56114 11905 7 +48728 27982 4 +56039 15264 9 +9292 47650 3 +16863 36620 4 +27808 38172 13 +53478 45071 16 +6937 45323 11 +13946 13013 5 +3514 17447 9 +49067 12701 7 +57567 23118 10 +32623 30754 9 +49558 1343 12 +25798 17978 15 +34765 30550 7 +44574 36009 9 +37081 12851 7 +34367 57955 12 +7526 16489 7 +51673 47581 2 +13010 29224 9 +11195 41162 15 +51528 27786 9 +6738 20348 1 +38507 40375 6 +17509 33741 4 +27151 57209 11 +21289 45739 14 +45108 1309 9 +48721 698 8 +11778 37130 15 +15388 3392 9 +22092 49870 12 +40996 48985 8 +57805 40662 8 +48924 46624 13 +15164 49176 9 +19071 22519 8 +15667 39987 9 +17697 38368 5 +1565 3812 7 +16009 56663 9 +44038 30308 10 +9546 23174 6 +17201 52443 12 +21597 20208 6 +9653 40979 7 +30872 38140 4 +45836 41936 5 +31120 8178 14 +40893 28348 16 +16294 37319 10 +38035 23907 6 +18088 45565 8 +16136 51046 4 +56488 43088 3 +21448 20611 5 +37656 55364 9 +39724 22749 9 +2022 52937 9 +16892 36073 7 +38513 9658 7 +58855 13757 12 +52679 29760 8 +51234 42869 11 +10875 42984 14 +52791 38361 10 +17206 22860 7 +59727 54826 8 +49213 23766 15 +3882 59340 8 +8949 51704 14 +35512 8105 13 +35520 2793 12 +47100 29107 13 +55741 56182 14 +58711 46361 10 +36003 29423 14 +15445 25468 5 +55018 23628 12 +43052 28465 12 +31496 14130 7 +16692 55404 7 +18366 49324 8 +2345 31130 15 +58810 41217 3 +29272 6630 6 +23592 15422 11 +5246 36488 3 +57887 15085 5 +36970 57996 11 +31299 34293 12 +43409 21519 10 +51863 11117 15 +52969 9299 8 +25680 4392 12 +51457 56864 8 +54937 1348 10 +36010 5265 12 +47166 24672 3 +21208 19198 7 +56567 36866 13 +39393 20183 5 +9585 6050 11 +56983 13218 10 +50782 14537 9 +37062 17538 10 +58295 30560 13 +19713 23539 12 +22366 25992 9 +5408 55539 12 +27860 24413 11 +49541 43374 16 +10756 33386 11 +45607 51824 5 +44957 10311 11 +48188 20523 12 +19108 32540 6 +24469 27193 8 +59402 5526 13 +38261 1968 11 +30237 55353 12 +59382 59343 9 +27365 57499 8 +57428 27756 16 +45673 24579 13 +15883 42359 5 +35873 7009 6 +58619 9604 4 +12243 32062 2 +16114 18703 8 +10860 28511 17 +10044 20212 7 +59743 10907 5 +2870 40908 2 +46600 36493 8 +47811 40466 16 +16721 31644 12 +42492 24844 11 +59456 23605 10 +22146 29290 4 +14329 54238 2 +36340 32973 9 +45412 35880 3 +56787 4096 9 +33976 18554 18 +13207 9276 13 +35298 23585 3 +28507 37312 14 +28370 32160 2 +49427 46129 7 +46540 35083 10 +56564 755 13 +12023 36714 12 +52456 1513 9 +3933 12778 15 +3902 230 9 +30336 5835 6 +25922 54062 6 +31387 9010 13 +50941 47829 13 +7131 4631 7 +21100 46086 11 +48732 44827 6 +10026 33241 7 +15840 36050 13 +42170 10241 4 +48275 18697 16 +44210 12746 2 +10888 12128 5 +31011 16797 11 +17789 33954 12 +30937 55883 12 +53813 11201 10 +17093 53551 10 +13391 22783 12 +29351 49252 8 +49354 33144 9 +30413 37219 8 +49601 30784 6 +39152 10071 1 +28441 52325 4 +36847 56997 13 +8244 33093 16 +59773 26698 2 +51837 9400 6 +46824 1477 9 +44541 14647 11 +30912 40133 12 +347 36025 6 +29768 16102 12 +23042 59949 17 +11638 37514 7 +40918 14212 2 +23677 10222 10 +38097 13729 1 +20625 22544 4 +36998 12663 10 +87 45864 18 +28005 24822 13 +28014 39796 8 +16516 41995 6 +19766 57818 14 +37048 24117 14 +9366 15450 11 +15411 25781 9 +11992 11046 13 +43622 13308 13 +50851 50227 16 +27464 28930 9 +56609 15485 7 +1753 12662 2 +32431 38150 10 +32819 28733 13 +25155 8696 11 +16046 37280 5 +41670 49968 8 +5644 8170 8 +54702 37294 13 +16853 43898 16 +17781 57785 4 +51268 14359 4 +31190 2276 9 +12790 57331 6 +31390 48356 10 +26935 22483 16 +9288 53182 4 +52614 7756 10 +5541 26617 1 +43747 1587 8 +5583 19247 3 +35984 17212 5 +42834 27576 6 +56617 36109 17 +4117 7495 10 +49692 9311 13 +32224 30967 9 +33265 12345 7 +58473 39062 13 +9673 53739 13 +46542 27428 7 +22830 16428 6 +1820 59309 17 +58043 55742 12 +27216 35252 6 +30052 36602 9 +8769 50846 8 +24887 51400 11 +50810 32231 7 +15858 59833 11 +42283 13838 13 +10989 57703 14 +22434 24585 10 +38456 52566 13 +42780 51095 16 +37582 41793 11 +51801 27999 9 +7197 20934 7 +16963 49939 6 +42540 45092 9 +19186 58540 10 +3366 4849 6 +55463 4375 13 +43056 16433 11 +25651 8668 6 +21014 46591 4 +39296 59325 11 +35996 48896 10 +51642 58986 6 +55573 37003 15 +58775 5207 5 +27619 46747 2 +34000 11817 9 +33341 43057 15 +46225 22410 2 +20607 59956 13 +25340 13543 9 +18501 29342 12 +42698 11722 13 +51256 34696 10 +7976 29072 12 +819 22153 8 +43070 39965 8 +58608 13276 14 +5329 49518 6 +54966 41151 14 +5298 43791 1 +55710 722 6 +46852 23700 7 +52263 38836 13 +58363 43499 18 +9458 17416 6 +20433 54072 13 +30271 2970 8 +19937 45305 6 +34298 30714 12 +2786 24684 12 +33194 4294 4 +41265 24505 7 +16232 57287 9 +16377 25165 14 +34027 403 9 +56322 56394 10 +15130 29765 3 +49332 15507 9 +19259 5621 10 +7019 43570 5 +32187 23414 9 +58933 43755 16 +45463 43296 9 +5257 26038 8 +58170 53204 9 +22507 36145 9 +53719 21994 11 +17146 23480 12 +44144 39123 12 +13999 5401 10 +53486 10700 8 +6729 39306 4 +3946 38710 8 +6915 22109 14 +56896 59554 16 +59797 5658 11 +2940 3145 9 +26061 44364 10 +55303 34202 6 +8764 54606 15 +45465 32462 10 +23620 6814 13 +41784 36941 5 +12553 33365 5 +21750 3818 11 +56973 53383 3 +35915 17443 12 +30954 55238 11 +38917 33377 10 +51876 43344 2 +18374 54711 9 +32430 56489 2 +35695 27770 11 +52636 33745 6 +50793 50637 6 +10335 36263 9 +57067 2929 7 +30993 32723 2 +6361 7703 11 +20837 53678 5 +41238 29335 9 +17265 43451 7 +16072 32935 13 +59806 54096 8 +58848 58799 12 +20027 2163 7 +43841 30429 9 +32271 19832 18 +45915 8895 5 +18048 57518 13 +44867 33591 2 +38788 57838 9 +31934 5538 18 +7242 22553 6 +20682 7759 12 +892 34120 9 +47288 57140 12 +46691 32126 8 +985 2305 7 +36175 15437 9 +4664 19928 10 +34173 18091 10 +26982 20835 11 +18094 49901 14 +1660 49418 8 +17057 39528 10 +22931 58085 6 +48699 41185 7 +29680 23305 8 +3260 49173 10 +31972 1152 8 +10621 21736 9 +14784 26879 10 +54549 30870 8 +30151 43015 8 +42808 51198 16 +11902 32203 3 +2665 37734 6 +3179 27325 11 +32443 16155 13 +25800 41239 10 +31741 46202 13 +46505 21430 12 +21374 31848 5 +37070 27379 12 +41932 8011 13 +17496 4601 8 +13434 27244 8 +6343 51873 10 +21019 41484 3 +15831 10632 14 +28137 38455 4 +25248 45442 9 +635 48891 13 +22057 7246 12 +52948 58879 9 +4460 37131 11 +24072 2848 7 +36495 41119 6 +48828 39589 14 +54375 52027 5 +52609 25696 1 +5215 47413 12 +28455 38781 12 +25713 33097 14 +36022 3545 1 +21792 17469 8 +18435 48446 4 +22954 5082 0 +23889 19342 4 +19772 693 2 +10532 36314 10 +4112 28848 13 +29868 23437 17 +33136 3288 6 +42776 29494 8 +45293 13930 10 +25848 3268 10 +11229 1171 5 +49256 34568 11 +58223 48286 4 +36173 5348 13 +29612 47981 6 +44912 27129 11 +25045 16396 1 +51752 24787 10 +44370 537 6 +39961 57812 8 +45023 23054 13 +23600 2723 12 +10083 36303 5 +16056 15666 15 +58213 29652 16 +45315 29165 9 +54783 41412 0 +1580 34859 10 +50829 3660 3 +39394 5591 11 +13453 38990 4 +12151 56757 4 +42522 10304 8 +5731 51028 5 +23065 51736 10 +46303 41420 2 +45921 57882 1 +29640 48339 10 +40184 9490 11 +26913 31702 10 +43237 59750 10 +15090 25674 11 +38559 41516 2 +42598 24561 9 +468 19875 11 +36839 28081 9 +32675 1379 5 +16305 26033 3 +23674 39847 15 +56914 48307 5 +59367 47043 6 +10011 9417 9 +10915 6381 8 +40775 54127 9 +50509 51486 9 +39497 3879 9 +24894 20014 12 +4795 9344 8 +14591 22268 10 +25676 57139 2 +47909 48437 15 +54970 716 7 +7112 49593 11 +42445 463 8 +30584 54722 11 +1156 50085 9 +5311 17175 9 +15653 15349 18 +14354 24528 4 +23254 27523 7 +56247 28917 8 +7390 11371 6 +12834 48327 10 +36229 40440 11 +28868 4328 5 +45933 5377 7 +54871 42006 15 +5270 9444 10 +30987 3322 18 +8131 38928 2 +26094 49051 13 +37367 39631 2 +40930 1192 6 +44165 17100 8 +26259 33529 12 +50524 35970 10 +7248 16448 8 +33412 39913 10 +23566 35170 9 +52615 28695 2 +48656 28078 8 +22274 28478 13 +42398 8838 3 +12424 40279 4 +33525 16612 11 +44898 80 11 +20728 33338 11 +56961 49388 11 +58963 22862 8 +20170 21455 14 +20398 25153 8 +16320 46769 9 +18615 46128 7 +2631 3309 6 +8872 37593 13 +15522 35656 12 +14960 53524 6 +9893 42144 18 +46655 1666 17 +22452 38527 3 +38923 45638 9 +57878 12658 10 +58828 14217 18 +37618 5903 2 +26219 7454 1 +39218 48676 4 +29938 36132 12 +47375 48909 9 +21618 56267 5 +11003 44287 6 +5975 15862 13 +59289 52995 1 +42375 21522 5 +41921 34910 12 +12315 32272 13 +12414 28280 5 +19021 21211 14 +13441 39101 8 +44082 53120 11 +1336 35761 4 +50669 5788 5 +8155 55729 14 +43790 49602 4 +12011 41605 9 +21047 44945 17 +13197 26855 4 +34461 31613 9 +19423 2777 8 +2824 56821 4 +41107 1109 8 +5623 19303 4 +48385 26767 7 +3480 22056 10 +6094 30700 0 +16668 808 9 +5158 53273 6 +45704 25368 9 +32425 13789 11 +1693 49948 7 +43740 31501 8 +49395 30866 2 +41125 43705 5 +59064 56168 7 +37985 55600 11 +44947 18619 17 +13075 31763 5 +47652 42839 4 +56049 13107 3 +52930 44714 8 +7193 18070 6 +33434 24412 13 +37285 34225 9 +317 42179 3 +44186 24821 11 +25018 12771 9 +41931 33951 10 +7200 46546 11 +39313 8306 14 +45011 35075 9 +42185 24715 0 +2077 45230 8 +59694 44450 10 +24873 4420 8 +16556 25195 11 +56844 22618 13 +54670 35101 12 +16796 44849 13 +41248 25465 8 +55698 7841 6 +37542 55920 7 +55493 21338 14 +29931 3307 9 +36914 34059 8 +38010 41155 11 +58768 2054 7 +23777 58921 11 +36958 14060 3 +18421 55861 7 +2602 41574 10 +24614 57911 7 +17060 56329 15 +4729 19267 8 +32282 33680 9 +38537 44406 12 +405 48409 9 +51667 49674 11 +36533 51706 3 +34786 39388 15 +54438 38127 3 +13985 50612 7 +34932 20409 6 +18347 9630 14 +11924 35378 11 +23055 59838 12 +7241 52048 9 +52265 6370 11 +36061 18100 13 +42031 27764 12 +45609 34908 11 +4202 19861 1 +53817 54792 15 +53777 11430 13 +20063 32128 13 +14946 32742 13 +22391 49331 2 +37642 29734 2 +52319 24915 3 +3426 58328 10 +10091 45728 3 +43480 16943 2 +36457 13180 8 +27478 31196 10 +6000 43940 12 +7211 53022 13 +9551 11815 11 +9218 26246 6 +8640 49973 11 +35452 48850 11 +56587 41229 8 +24638 45653 14 +18843 538 8 +27937 42134 10 +6385 42464 9 +20127 9147 12 +59350 51369 4 +13558 12095 1 +3148 48183 9 +37927 18273 3 +6434 18579 14 +38948 5634 14 +27695 29692 8 +2085 55117 9 +38248 27571 11 +1689 51160 11 +37689 53754 9 +22551 41402 13 +7302 28577 7 +18548 52876 10 +4886 32396 15 +34389 14657 8 +9069 17105 4 +12200 56335 11 +47554 29194 13 +34814 57622 14 +48591 8592 15 +44922 5029 12 +43140 35309 11 +35220 50820 2 +47611 32966 6 +37380 3997 8 +30174 56025 5 +39103 26430 14 +21456 1611 10 +12540 56570 5 +5358 7870 5 +44184 11170 7 +6026 9788 12 +3687 22130 8 +23965 23783 12 +45652 53094 14 +20424 12421 2 +256 42958 8 +10199 21037 13 +15761 14184 3 +24069 41268 6 +43807 34589 12 +31957 28469 12 +33474 51445 10 +38618 44254 9 +44862 47952 5 +24931 40255 8 +59292 24519 11 +56492 46386 5 +17843 53685 6 +32371 21753 9 +27159 45987 6 +24456 34045 4 +15527 58557 7 +24806 79 15 +20666 26143 13 +36637 2537 11 +28114 53732 14 +5293 18301 4 +21795 19830 4 +13039 4340 2 +51691 20730 11 +4562 26902 14 +32150 25700 9 +25788 2909 14 +36860 26624 11 +25360 616 12 +43340 12105 11 +16400 38939 5 +14887 38144 12 +9182 26084 6 +8122 10900 6 +21249 30640 10 +16780 15736 7 +31380 26881 8 +47062 51107 12 +5794 7834 10 +7310 54474 9 +31353 20423 12 +55626 15613 10 +25410 15129 12 +17820 49650 6 +22328 20830 10 +29093 38206 10 +39418 22619 12 +12314 32295 2 +44770 16672 8 +14441 54435 15 +46804 33402 15 +56559 25766 9 +41725 13808 7 +16653 9930 7 +41517 56350 10 +51981 26836 9 +45538 50376 11 +41625 58262 9 +12677 31139 11 +32420 6874 9 +34010 34020 9 +35446 23391 15 +29120 31304 7 +56321 58264 12 +2760 21279 3 +49651 36940 10 +26891 42811 12 +12869 37843 1 +10536 26854 12 +7886 24472 13 +28009 7650 8 +44294 42174 10 +1496 14910 7 +8918 10967 12 +8239 22793 6 +53160 59439 1 +3081 17050 7 +7254 4983 9 +6977 39466 7 +4867 29709 13 +9729 31532 18 +19639 33768 10 +56196 19066 13 +3594 4009 9 +29863 25090 14 +16714 11382 9 +1057 40565 7 +10394 41356 10 +46008 24990 16 +19755 48744 8 +21741 20643 2 +52323 46528 8 +19048 47257 15 +3883 7228 16 +32038 33606 10 +20942 56873 10 +35529 49951 4 +48153 46022 10 +26123 26479 4 +26239 56435 6 +11408 32107 9 +23370 39294 9 +7815 21079 11 +30617 11883 7 +30793 46262 5 +46906 9647 12 +20532 35281 8 +4722 4626 6 +54600 11480 3 +4298 36351 7 +8245 32260 14 +14495 28462 12 +5202 10288 5 +53830 916 11 +45066 2362 1 +49184 20475 8 +28644 25146 14 +30864 34401 5 +4394 54020 10 +22881 46276 3 +3699 57341 6 +12486 38171 3 +52015 31671 11 +17560 3347 4 +11903 4932 18 +27748 30173 17 +32209 29535 11 +29599 48752 8 +39343 35647 11 +32168 28007 14 +18280 25038 5 +36452 50479 7 +44447 6429 8 +44171 57229 12 +14002 43188 3 +44096 41767 3 +45295 8311 11 +33184 52160 5 +56118 55429 11 +31269 32862 7 +46250 43798 9 +21950 22682 11 +19040 25789 9 +6501 34882 10 +6727 48631 6 +4834 58372 17 +58874 6840 8 +29550 42636 7 +18514 45363 3 +57617 41975 14 +29740 43584 8 +58784 37526 2 +16475 14940 7 +11660 37581 13 +13669 53033 10 +14871 58470 16 +51045 22215 6 +19731 3667 1 +9469 20082 13 +58429 58968 11 +52525 6016 10 +17572 1575 10 +50123 7174 7 +10399 6053 8 +33558 40232 8 +32800 49052 8 +19706 24327 9 +38078 52594 9 +34592 4426 15 +26880 2771 6 +38573 11335 0 +4023 56613 8 +26693 7945 11 +19391 40287 3 +9707 16654 2 +29789 40034 8 +16616 47022 7 +10014 36512 14 +11720 20446 10 +45185 3959 15 +40237 23033 4 +53554 31277 3 +8086 51622 8 +1116 6665 10 +23491 24044 9 +3447 26456 13 +52592 38479 14 +8308 57303 10 +3105 31211 7 +16270 27116 18 +48867 38019 11 +49353 12044 9 +48291 31365 4 +27208 4131 13 +28807 3058 12 +13390 49036 7 +36739 16135 13 +30073 15290 2 +38409 43837 7 +59352 11731 9 +5498 47153 1 +32106 5156 5 +5231 1481 11 +16240 30750 16 +39081 1873 11 +51500 27667 14 +11202 9627 11 +44540 29282 10 +30665 46371 0 +27783 40982 4 +14860 36760 8 +18622 48165 9 +44108 28892 9 +38606 41012 8 +2144 39097 2 +17115 837 7 +49914 8190 7 +11432 39406 7 +8075 26086 7 +6785 43383 9 +21277 45386 9 +59922 46595 7 +15235 53927 14 +11613 24304 14 +37698 21590 9 +52526 35608 5 +22330 47921 5 +35013 15654 18 +49394 20133 8 +5638 47681 3 +39767 30037 6 +23881 23487 10 +22755 21369 17 +30884 21086 9 +53181 53308 9 +5964 50570 14 +11454 45449 12 +24986 6482 10 +2885 30593 9 +15800 34243 13 +45885 37555 5 +54543 25084 6 +51204 31918 16 +27012 6160 5 +7673 55063 11 +38889 10383 6 +28243 32402 10 +26974 10339 10 +18948 29028 9 +38357 49482 2 +7629 56426 7 +29609 26570 6 +26647 22475 2 +27449 26188 7 +19673 55643 7 +37691 56308 4 +35417 43084 12 +33946 52967 9 +32176 33245 8 +58121 52427 9 +11193 30221 11 +18810 12231 13 +38517 35103 15 +102 37502 7 +35432 58636 8 +12760 55733 12 +20687 53402 6 +38189 57497 10 +43699 35889 10 +59429 11108 16 +14082 42112 17 +46924 56687 7 +54068 5516 7 +24458 48319 12 +53452 3007 9 +27165 11464 11 +5459 48988 16 +21643 47091 12 +24281 43605 9 +15720 16531 9 +14730 36338 11 +7787 12072 3 +52114 57129 9 +38988 22892 7 +32703 16272 10 +6710 46508 11 +41769 51497 13 +38963 14079 1 +13024 42968 8 +37182 35985 2 +50269 54313 7 +29642 40231 10 +21191 40196 1 +27105 55450 13 +8230 20302 4 +50635 28052 8 +32667 8850 14 +55174 18593 13 +19717 46424 8 +25509 55724 10 +20512 29852 11 +36007 41942 18 +30367 18305 12 +29832 26348 8 +21996 32987 5 +27512 59710 7 +22693 31151 11 +14142 53834 13 +37198 19162 13 +8261 50689 6 +55646 6271 4 +41578 8235 12 +28968 56421 6 +27524 55005 12 +46447 33683 11 +48335 16054 7 +6398 49208 3 +6213 51250 4 +29054 52423 11 +34929 25988 16 +19461 55105 1 +40414 20099 3 +40454 19572 7 +13444 32359 13 +56503 42171 8 +17501 53920 14 +54281 59999 13 +14945 33595 7 +36399 34621 10 +23790 29189 14 +31121 25684 10 +10306 59702 15 +44177 11681 17 +12179 52346 13 +18112 56187 4 +3670 58396 3 +40790 53580 9 +18286 32073 9 +15748 5510 5 +40740 5689 6 +59897 19793 5 +4441 21990 2 +48404 690 12 +49769 14997 13 +448 39475 8 +23458 54045 13 +59596 974 10 +12459 52735 8 +6332 48454 1 +51103 30390 12 +49920 34321 13 +13503 28277 7 +24685 47556 15 +47925 14316 8 +54459 33513 6 +46840 35014 3 +7438 20153 13 +16708 30867 11 +50931 29226 7 +16287 20004 8 +29780 2757 14 +28303 56832 10 +49722 48050 11 +13234 11886 9 +30898 23667 7 +39500 28461 11 +35094 50504 3 +59644 10204 9 +17866 18005 12 +38611 23730 12 +12484 26816 9 +33004 42393 4 +12921 24250 12 +38547 21152 6 +32840 10290 6 +37949 54550 16 +5416 25320 15 +15496 4206 12 +22650 55144 8 +17609 45093 11 +22957 56728 4 +11627 44905 8 +56710 25064 9 +4098 14126 10 +39653 44452 14 +51944 28973 4 +19958 49375 10 +44156 48667 10 +40973 18460 3 +46868 52558 0 +20452 7270 12 +54532 39230 12 +11628 39131 17 +34472 48314 11 +10683 53060 11 +53924 23575 9 +33323 7735 13 +2837 34685 9 +29930 47721 3 +43890 35610 10 +19257 49801 16 +24664 51495 13 +16947 49915 10 +26153 29076 13 +15949 48819 9 +57001 24160 16 +28578 47134 13 +53651 5543 9 +13840 57245 3 +15005 1026 10 +37875 29314 9 +27589 17454 3 +44555 40341 12 +5180 42823 7 +24300 50503 15 +7603 1358 7 +13400 1712 5 +28098 16024 3 +29573 17141 6 +33320 42936 6 +28860 43519 12 +3104 56580 18 +9454 57204 14 +20190 46222 13 +28460 16545 10 +40732 56069 2 +868 50295 9 +37424 24041 16 +24725 7176 6 +3220 3677 3 +52321 37014 8 +13748 36414 1 +44991 49109 11 +31849 3455 11 +9537 9579 9 +11268 57367 8 +9951 8303 13 +39808 57493 13 +21963 30498 14 +30352 55479 0 +22390 40417 17 +3614 43750 12 +3457 1154 11 +26453 23911 7 +7847 54162 14 +13069 3452 7 +49046 41834 11 +22319 23570 16 +16318 36077 2 +13228 52516 9 +59447 31505 8 +1353 34023 10 +54296 41243 8 +40696 35388 6 +8124 17220 3 +6968 5748 3 +29193 58013 13 +13756 30324 15 +36443 34129 9 +53116 47944 5 +44308 46375 8 +36740 48582 7 +47587 16188 9 +48480 22589 3 +48184 9973 2 +31308 17536 12 +12086 59215 11 +6923 8089 0 +21372 18583 1 +51239 14557 9 +49170 29700 16 +12168 9041 9 +14147 10128 6 +45927 32426 9 +10538 43578 6 +53981 31178 9 +41978 49567 5 +17973 22178 8 +40526 52730 13 +7463 3270 10 +21740 30337 2 +37888 35177 13 +27190 54354 6 +29433 57988 13 +35426 47461 9 +24545 20114 7 +15390 944 11 +7074 24043 6 +15086 59811 13 +479 53666 10 +49357 9515 6 +51983 48052 8 +39310 50592 12 +32673 13592 12 +56215 33238 2 +7162 45306 5 +27038 56154 7 +40579 12377 11 +34966 58648 15 +30222 10644 3 +18821 15023 10 +23595 28766 12 +53677 20143 7 +8433 21539 5 +24383 33049 9 +14256 1647 7 +14317 23931 10 +8506 7777 9 +10848 5551 14 +52637 31662 4 +54028 11499 12 +22739 20228 16 +21367 23038 9 +47492 24910 11 +35954 13896 3 +5278 3819 9 +8466 32388 4 +27877 782 14 +54712 16082 17 +41972 30517 16 +47017 15873 14 +31799 43312 9 +8472 22823 7 +37170 33646 9 +37425 32017 3 +54989 38278 16 +55128 21028 8 +849 12472 4 +36142 3773 11 +25282 26035 7 +59677 46251 3 +16199 59355 9 +39363 53318 6 +14022 41149 13 +58535 22861 7 +27221 51195 5 +30524 8014 4 +10136 9649 7 +12774 24705 14 +25609 36400 6 +37669 843 5 +43134 57875 4 +44003 6678 6 +40320 29257 7 +39671 38982 8 +56231 46148 15 +39556 47090 8 +11725 32037 9 +41586 15352 10 +21169 20573 16 +15061 56259 6 +28776 49191 8 +59484 10696 10 +18426 58912 10 +45212 31798 14 +35507 21604 6 +50395 53495 9 +34218 49151 2 +344 44583 9 +34711 39145 7 +53647 41152 10 +954 51553 12 +49786 30786 8 +59485 14917 13 +1595 23502 11 +19773 5542 10 +24353 56903 6 +59513 51985 16 +1397 38986 5 +24702 18749 12 +18784 13855 8 +42103 33366 15 +52052 36965 9 +6175 24240 11 +25546 19239 17 +29755 13573 9 +16596 35763 16 +2770 23485 6 +30201 10344 13 +58258 57264 10 +34040 24147 16 +30873 5962 12 +59252 46072 5 +10505 57503 2 +41969 32931 6 +17740 3609 7 +38979 1498 12 +6958 46382 6 +32172 4678 13 +18866 52725 10 +39976 28291 5 +50158 29857 10 +42990 33073 14 +10869 32007 4 +11258 36939 13 +23234 29705 14 +7948 25974 2 +21684 47666 13 +42603 20716 7 +13429 13092 14 +43628 47779 11 +33484 48966 11 +29419 9786 12 +58061 51604 11 +42194 39737 2 +37866 31939 18 +16883 27474 9 +21017 26371 4 +3784 9519 16 +54215 3349 13 +11231 49930 6 +46220 20601 9 +22290 49709 15 +49875 28909 3 +4318 18448 13 +19620 45311 11 +34350 24026 14 +44911 15404 13 +8491 59416 4 +14247 26534 12 +16613 21267 16 +33597 9901 16 +58139 12998 4 +57977 35353 8 +9661 27830 15 +16299 40851 9 +23323 26092 8 +25200 17658 15 +17700 43192 11 +37023 5881 1 +39926 30198 12 +55586 12135 10 +59732 9164 10 +2025 8254 9 +59222 50684 2 +15231 21978 2 +4749 48126 1 +4647 30810 9 +22504 26200 12 +58917 16485 6 +10693 20009 7 +36348 44596 12 +38265 13399 10 +10658 12006 18 +2588 45477 9 +59361 20352 16 +56546 13463 11 +57928 37848 5 +53363 10176 4 +36691 54866 9 +12191 2375 7 +21931 51613 7 +11336 16659 14 +23222 59505 10 +6442 10467 6 +25120 59258 17 +55940 32103 16 +2796 8717 10 +37783 6020 9 +50131 39667 7 +52334 29943 8 +35327 48090 6 +43725 8231 16 +43654 49903 3 +30952 5181 14 +45636 9002 12 +22093 40230 7 +32766 49540 15 +13089 44676 16 +46410 21974 3 +39537 40435 16 +4383 36702 14 +10262 55073 8 +58088 28423 9 +40532 25531 4 +16821 51989 11 +58143 52661 10 +59504 46735 13 +46695 12715 12 +49822 5209 17 +25445 29901 9 +18775 13921 8 +52355 55315 9 +13248 4124 14 +48907 49683 10 +9719 4523 15 +35277 40718 9 +22685 7755 17 +47758 41237 2 +52858 11599 11 +21224 7152 13 +47530 7981 2 +43250 55163 16 +33961 22003 12 +43369 54192 9 +30681 11063 11 +36082 22509 8 +16553 14516 6 +32910 20005 15 +51496 35034 13 +13725 39060 8 +27882 7776 6 +14819 12134 2 +55267 50400 2 +37406 8958 11 +8661 48092 16 +35153 12756 7 +16836 21288 8 +8095 30422 5 +51895 28690 1 +51760 52591 9 +5374 15834 11 +45686 14705 6 +48954 8711 6 +46858 21141 7 +33863 21269 6 +26728 11530 6 +42086 766 17 +31683 55338 1 +25237 28877 10 +44903 40637 5 +6406 25777 6 +36731 34465 5 +19188 52496 9 +19557 14261 11 +28289 16758 2 +50128 43442 14 +20631 54468 4 +44503 4163 7 +53670 43515 8 +49559 59154 1 +8065 57916 3 +31903 28773 9 +57789 39002 7 +23713 45720 11 +7657 59791 10 +19771 54636 15 +51143 7702 17 +59713 6251 4 +53695 12037 13 +32762 7172 9 +57256 39628 5 +21243 3624 11 +46589 5096 9 +41029 37252 1 +58776 56248 8 +1446 26274 11 +6932 33223 10 +11605 48332 2 +27419 51548 4 +40560 8794 9 +1001 35646 7 +16395 36110 8 +24400 13528 3 +45687 42064 10 +16230 27497 15 +13661 14470 13 +18550 27863 14 +40823 58866 1 +11568 40506 15 +35450 48141 13 +41452 43964 8 +49188 7878 6 +59512 15477 6 +12664 18504 5 +28591 19029 7 +56981 15462 11 +21762 24761 10 +59031 51415 7 +34273 35561 8 +17161 58145 11 +6875 52810 3 +23861 24223 13 +17380 1906 13 +57743 45070 10 +54005 13761 3 +10787 15503 12 +49972 58388 3 +26112 38627 8 +59143 48457 9 +42360 2818 12 +17420 54034 15 +36862 51330 11 +30443 26733 4 +10106 2521 11 +25837 17727 10 +9108 52358 6 +45225 16830 12 +33082 3326 12 +2706 52374 13 +59853 22612 8 +53195 46207 6 +13196 15967 1 +2086 19003 8 +23819 30085 12 +16216 59918 4 +17314 29039 0 +10317 11446 4 +39739 2108 9 +45312 40690 3 +42928 31803 16 +46551 58322 3 +22354 9384 10 +20841 30645 12 +15863 35033 6 +25034 12042 4 +25893 3040 14 +19171 59495 8 +18187 50398 14 +32573 44547 17 +46380 9621 11 +19110 8975 8 +42244 49367 10 +30219 7915 11 +25392 1855 16 +2080 37354 6 +1235 25581 16 +53279 38394 15 +15705 35433 13 +41225 34777 4 +35419 52895 11 +49705 41922 5 +20270 16962 16 +21253 20466 8 +56102 17991 13 +4428 3538 9 +7567 42282 9 +13053 13420 15 +8297 52470 7 +32095 31310 7 +1524 52020 6 +5076 19683 9 +4246 57372 10 +45899 42395 11 +58829 24194 9 +37373 37733 10 +35105 35473 9 +26672 6838 17 +26271 55474 10 +6711 39461 6 +38535 44582 7 +2145 9479 9 +56136 20635 8 +59586 54552 2 +7494 22821 12 +50260 6594 6 +2648 47839 4 +53975 35286 4 +31569 50344 8 +24762 8676 6 +24763 33685 5 +37822 1265 5 +36768 35510 4 +19783 9070 17 +5558 50877 16 +32194 22089 8 +5475 9578 5 +30815 28543 4 +5507 12261 2 +18970 2382 8 +30655 21862 8 +13114 6451 8 +27869 24473 7 +20530 50252 10 +13660 59189 4 +18801 54504 10 +16406 40816 7 +49239 25150 9 +32446 6445 3 +56315 59531 14 +51208 7851 16 +48456 12748 1 +20141 4333 1 +51905 9266 3 +28296 20580 8 +26899 53697 8 +31878 25439 16 +12537 3751 14 +4320 40051 12 +42072 39805 7 +4116 14113 9 +3942 56181 7 +19474 2884 9 +17457 1951 7 +13227 48087 5 +38813 17511 13 +19636 20887 8 +28916 17020 7 +20334 19295 9 +56338 33555 6 +43110 27215 10 +28685 13432 4 +39546 44363 1 +52745 10999 3 +53296 33156 14 +20435 9451 7 +32611 16781 4 +7827 10411 4 +52705 30889 9 +18717 13846 10 +47068 21906 8 +25600 41226 2 +26048 1257 9 +51191 57353 12 +25709 3231 8 +46690 12180 2 +5729 29936 3 +49229 15114 6 +1103 31968 17 +29168 52557 15 +39149 59035 14 +44497 42257 6 +6100 33321 14 +45219 53312 12 +25363 43026 11 +27098 29011 11 +12438 31870 5 +49604 23256 11 +28480 54267 15 +14644 59473 5 +55902 45824 14 +7227 31092 6 +28984 4521 17 +19381 33942 2 +46062 36248 6 +6563 31726 16 +35064 39769 7 +7180 24879 10 +41573 13844 5 +41369 57454 10 +7801 33285 6 +889 33737 7 +40419 16144 7 +42030 34749 8 +38258 14205 9 +36367 56934 11 +28727 415 14 +31901 43425 10 +1373 56875 7 +42854 34629 7 +58148 47201 9 +37211 1955 14 +10834 605 5 +18492 55659 8 +56901 31370 3 +22720 20758 13 +37667 54895 10 +7478 58773 10 +26366 24177 2 +4134 26199 14 +12417 45668 15 +5684 29689 13 +52681 19480 4 +29830 52746 13 +39340 54488 14 +19938 19470 17 +18096 8697 12 +26835 28503 9 +42075 14676 12 +32249 21301 10 +24542 52063 8 +6880 59870 4 +9750 19217 4 +17303 29331 13 +39763 9078 7 +49373 39047 11 +17552 23958 10 +25721 15837 12 +11772 49004 8 +5105 49050 8 +4311 57289 3 +16370 47394 4 +8785 26470 14 +2731 7113 8 +49236 7408 7 +47277 26747 7 +13920 10041 16 +20799 53222 9 +19427 29104 7 +15989 27001 5 +51699 48392 5 +44124 27674 10 +9646 54489 6 +50153 33776 2 +27463 56384 8 +43716 277 7 +34082 55542 7 +12870 30588 8 +6552 42250 4 +9900 51081 12 +18227 29799 10 +20620 9908 11 +20720 50435 7 +26386 19467 10 +12146 45858 6 +28529 19786 7 +28015 49338 2 +43349 2641 3 +39411 11248 3 +41943 51515 7 +3778 55204 5 +47077 7185 6 +48343 58036 7 +11670 44075 13 +41446 50468 8 +53459 51909 7 +3895 32351 16 +33819 47061 9 +13774 26352 6 +15556 25010 10 +14613 18727 3 +21009 50715 10 +42353 30772 4 +55393 31316 8 +21033 22299 11 +5600 41597 13 +7784 53136 6 +21564 17801 10 +57961 14034 1 +21833 49824 13 +17196 59795 8 +12599 21016 12 +2584 54588 4 +26176 16382 8 +21121 44256 6 +16034 59256 9 +57929 2383 9 +22538 25706 10 +2127 16975 3 +45391 10612 8 +55714 4520 7 +43441 51083 3 +10746 39344 17 +34033 5314 3 +57033 57609 16 +19790 48532 8 +8951 48320 10 +10757 44871 3 +46771 26403 10 +48363 47862 3 +22985 24038 5 +9589 56506 6 +58833 12625 7 +50478 9269 2 +9563 20390 6 +55663 32646 5 +42646 24654 15 +40781 32449 10 +53342 34338 18 +36375 17786 4 +41322 27308 9 +29957 18364 6 +828 8284 4 +36634 47532 8 +12873 44623 11 +13575 47706 8 +20351 40115 0 +36453 50899 7 +33501 47840 6 +1650 50422 10 +30626 29277 12 +36559 21214 11 +41985 50672 5 +32340 22874 4 +45031 3956 4 +13159 35025 10 +29520 55132 8 +25636 7742 15 +18239 15469 15 +33121 23718 7 +3710 32981 4 +55068 7902 14 +7975 50510 13 +23231 2116 11 +5893 54249 12 +23947 51413 14 +29329 39619 8 +21780 27536 6 +59967 50472 9 +13620 13596 17 +15386 38585 7 +33797 50093 13 +36071 20551 1 +53502 15181 3 +38297 16060 2 +46084 30826 9 +34827 19296 8 +57797 54645 9 +49458 40243 14 +15542 41693 5 +44980 43495 10 +13461 57993 17 +1327 52387 12 +57551 1622 18 +14669 23327 17 +8219 3350 5 +33322 31996 11 +17624 39598 12 +37450 13496 7 +32397 29874 14 +7341 29243 6 +23333 10676 4 +27253 2449 9 +55924 48303 5 +33453 16452 14 +4291 25175 5 +7410 4751 2 +43469 19567 10 +59701 5003 11 +44987 49506 14 +36190 48508 8 +19434 29347 8 +58670 21977 8 +37965 8477 13 +47688 23652 4 +32159 54915 10 +23394 6792 14 +27909 1424 15 +48304 54289 14 +5495 1748 15 +42260 18700 10 +47456 28496 15 +10246 52984 7 +8022 25006 9 +20110 12034 8 +33698 38423 10 +37559 56949 0 +19406 38891 8 +48569 45670 13 +45635 49374 6 +51608 4970 3 +45536 39978 10 +39596 48383 10 +17414 21606 8 +57486 1082 7 +16719 32078 12 +17397 40433 12 +21045 44384 17 +45285 617 14 +26122 20807 16 +22564 42417 12 +48690 59822 9 +28030 24675 7 +50664 53403 7 +36582 1215 12 +59508 37571 6 +50365 1222 12 +32894 1983 13 +6196 27690 11 +44241 37830 13 +25863 15708 13 +26195 32968 13 +5673 6143 6 +10248 33769 2 +1392 20140 12 +17124 58510 0 +25218 47414 9 +55758 4585 4 +9848 46121 11 +46357 21013 9 +37758 8227 3 +21727 13841 6 +20304 37766 9 +51658 13874 2 +52162 18716 13 +21666 45194 15 +23073 36176 12 +59815 19590 8 +25679 26604 6 +51478 53943 3 +35480 21842 18 +54510 39329 8 +55657 33804 4 +40141 19638 11 +21110 25831 12 +2105 183 11 +18211 51805 15 +18136 11990 13 +26736 41286 5 +38759 2523 11 +21046 11250 10 +9165 25921 8 +35882 18679 5 +5015 49507 7 +20733 54824 7 +23357 35590 7 +7146 1094 6 +46470 36635 9 +8481 27816 7 +2980 36210 15 +46914 27634 6 +57524 26042 13 +21366 53468 3 +40773 48835 9 +2405 9314 13 +4224 40298 7 +10840 28977 2 +22795 31899 16 +20987 12522 9 +12496 13990 17 +22376 26183 2 +5512 27334 9 +51036 50405 13 +11756 10465 8 +41334 11988 13 +50742 25415 15 +22521 54185 17 +1312 28889 12 +1902 28356 11 +726 35320 8 +51306 33901 13 +56157 30771 17 +42122 27021 11 +5839 31113 6 +57330 4999 7 +7662 9484 8 +24349 41479 15 +1160 58638 6 +8476 53248 15 +42959 46991 13 +16940 146 11 +49967 27181 6 +52126 48247 7 +32855 6159 7 +44209 32346 9 +49614 53091 5 +54923 37762 13 +24502 22876 14 +27 32181 11 +2070 51424 16 +36825 53095 14 +8740 41360 3 +55672 32259 13 +40311 16157 12 +33115 56081 5 +45232 20572 15 +31908 48558 5 +31400 57453 10 +57566 10736 9 +23184 17399 12 +18487 20708 7 +52077 18325 10 +54700 28895 3 +41218 8579 12 +21881 35051 4 +51121 46060 5 +53668 30715 8 +4306 38830 14 +33351 26950 12 +59294 7502 12 +51578 10080 3 +9839 24424 9 +39365 19337 7 +1429 32327 10 +9429 32503 15 +37204 36490 4 +33812 9545 13 +10859 56690 9 +34330 43021 14 +28862 13631 2 +30207 17147 9 +24348 47225 3 +6340 41275 10 +21000 21077 11 +24737 32262 5 +54872 21217 8 +1473 36811 5 +47079 58189 1 +29888 10545 8 +13493 178 8 +9189 5266 4 +571 4942 9 +43715 58457 1 +35053 48089 16 +48784 19333 5 +22550 3389 15 +701 49134 7 +45175 20111 14 +58581 39202 2 +52565 5511 6 +6571 441 15 +4025 35640 12 +19290 47210 10 +37302 31032 7 +57629 54358 4 +58347 7542 5 +51879 29485 11 +41652 17245 8 +44373 26333 5 +17631 48274 5 +17876 4914 8 +58547 2880 11 +18432 9747 13 +43797 48495 12 +8471 8119 6 +59227 45577 4 +2308 40446 14 +40145 21691 11 +1934 33873 11 +669 15771 5 +16794 44008 11 +56539 26212 13 +21916 50615 9 +16159 2531 4 +12457 53890 2 +25463 2674 14 +32362 14920 12 +57833 21411 9 +56363 4655 5 +56459 51502 7 +40673 28344 11 +30917 59022 12 +19047 44410 15 +37416 17154 5 +43062 10249 17 +57060 15457 10 +44603 9744 0 +28477 57427 7 +1120 26047 15 +1994 34326 5 +38338 28583 8 +37330 41717 8 +4404 33216 11 +24489 25997 14 +23109 17645 13 +31682 15923 12 +11677 26097 8 +55786 56891 9 +8892 4768 12 +13365 41607 9 +2059 33925 10 +25178 7708 5 +11300 26175 10 +17532 23448 15 +7159 7015 11 +37457 15698 14 +14110 8632 2 +42058 34444 3 +34636 54425 8 +10727 28923 7 +59890 36506 9 +36328 48157 18 +39686 43660 12 +16430 26150 11 +27256 56516 5 +34958 29903 0 +14075 3740 11 +49064 16789 9 +34808 41179 6 +37278 25373 11 +50488 41914 8 +7779 22228 11 +39312 5232 5 +11803 8193 6 +18898 40403 12 +39112 6316 6 +41765 14462 4 +34419 49680 10 +20480 4200 13 +40139 49044 14 +894 27503 6 +21146 35594 15 +55360 15770 2 +49503 22781 12 +53247 57774 16 +38501 33008 2 +17992 32941 9 +15265 33480 2 +4976 27631 1 +35667 53193 5 +22458 52013 16 +44369 17628 9 +1431 18772 10 +4041 49877 14 +11181 22198 10 +32883 33467 4 +8269 5066 13 +15959 13538 6 +33141 44229 11 +23785 30788 12 +39684 5949 9 +24678 21074 7 +53516 53520 14 +23613 51806 7 +54829 16510 6 +28701 9841 4 +48796 35289 9 +35063 58706 5 +38553 10635 8 +23121 51453 8 +8232 57339 8 +4090 43479 8 +17752 49675 3 +28375 38785 7 +22076 14230 4 +39845 4386 11 +5987 27176 8 +50333 30023 7 +22816 46665 6 +30177 5698 7 +1843 696 5 +22837 36269 8 +22277 51955 11 +18742 688 5 +13027 44768 7 +51255 11095 6 +48171 49821 12 +2775 19879 13 +20031 57141 12 +5223 6218 11 +17065 14969 15 +34806 57766 8 +22388 7325 9 +9710 33297 2 +21118 10768 12 +7042 17953 14 +44720 23750 8 +30226 6511 4 +15134 59779 13 +59812 45694 16 +8731 50214 8 +33927 234 6 +736 1387 8 +45692 53376 11 +15719 1219 12 +43377 923 13 +7231 37723 8 +35568 36586 3 +20683 39155 9 +20711 2361 8 +56006 24709 10 +24957 2957 7 +36887 51637 7 +29420 28659 6 +49412 40676 13 +58496 53335 12 +52441 27158 13 +55979 17249 14 +3733 47597 9 +13909 21500 7 +47172 33416 1 +10436 48737 10 +40754 17054 13 +58629 52269 9 +18367 32138 8 +22592 10903 11 +38492 16298 3 +9804 8351 2 +35171 8493 7 +25040 23955 6 +55011 26019 8 +11833 18162 5 +7223 9724 9 +13490 17935 9 +18087 56514 9 +55471 12393 14 +39566 29552 12 +36663 31787 6 +36217 57913 14 +1331 46327 8 +36802 23567 8 +54842 13867 15 +14117 16028 14 +13827 929 12 +23111 8897 9 +24057 8542 10 +14342 4799 9 +21823 39052 8 +16929 44934 6 +57754 55538 10 +36183 50322 5 +56437 39195 12 +41305 58977 12 +2752 16999 14 +42863 31652 14 +2261 29139 10 +56034 42358 7 +31516 12991 10 +9617 55934 10 +49081 15570 10 +58826 57969 8 +29407 16194 8 +32680 55108 8 +565 7316 14 +35391 36723 10 +28039 31552 10 +34743 40331 15 +41409 22578 4 +5531 28198 11 +21681 35454 2 +35400 51728 6 +44550 37910 17 +32632 30241 4 +31587 20516 11 +6382 30296 18 +58419 38252 10 +37892 45085 8 +6179 35616 6 +50818 38378 11 +51480 49147 9 +47092 30863 8 +46416 18527 4 +25347 26 8 +33436 26428 15 +59986 29672 15 +55469 24142 7 +58517 11374 15 +43174 31311 12 +42708 24858 2 +40510 51702 9 +52618 941 10 +24921 36676 9 +4189 26957 14 +11715 29092 9 +16522 36321 11 +39929 33282 6 +24376 27584 5 +10518 33060 5 +17346 25913 14 +50307 3886 10 +44834 45763 10 +45596 42743 9 +10786 54458 7 +35021 4037 13 +38662 15036 6 +24382 34940 16 +51861 53070 17 +6809 7499 3 +24744 4893 11 +46560 42925 0 +54007 1710 5 +53591 20924 7 +32439 42738 10 +51783 26571 18 +17800 57841 11 +53773 52267 6 +14729 6448 4 +16266 14481 8 +50441 11273 10 +59664 10400 12 +29694 11664 14 +59673 40940 9 +43860 10485 14 +10085 28604 10 +603 37012 1 +58384 28117 15 +51224 18951 15 +54694 27911 3 +7964 50216 9 +25105 50169 11 +7386 51412 15 +59039 53931 13 +25751 50001 9 +37819 40195 15 +3416 16711 12 +38495 38148 5 +32748 24869 9 +31398 19749 8 +158 23201 11 +3840 9553 10 +46070 58762 11 +9498 1231 14 +53769 5040 11 +55581 7609 9 +3109 57513 14 +57455 50225 3 +39459 44408 10 +37879 748 14 +36365 35319 11 +57576 9918 15 +16629 16439 5 +13306 7599 7 +8135 39464 12 +27654 32531 9 +25762 46376 12 +23400 44963 14 +17215 14159 10 +55668 19456 12 +1791 44298 5 +51334 53832 16 +12288 21817 12 +28426 466 5 +25457 52466 12 +44292 26088 12 +59027 29716 11 +8750 56984 9 +13914 19862 7 +46194 30057 7 +57992 53425 3 +35299 44508 6 +19943 23946 11 +46649 27578 9 +32220 26956 9 +40574 48915 5 +12083 12901 8 +1149 45137 8 +17324 9947 8 +49944 6841 11 +42396 29808 15 +49596 7911 0 +12528 49941 7 +57946 58689 5 +28501 24548 11 +17149 38414 5 +46607 43472 7 +59564 35497 15 +23796 28046 8 +47932 27287 9 +47249 39189 5 +45057 9950 17 +55916 24871 13 +40315 26645 1 +5685 38023 10 +27141 24646 12 +25813 6221 12 +36343 32491 15 +11148 59876 10 +17274 3158 11 +16524 58732 13 +3709 57780 1 +35028 55169 1 +24296 248 5 +32815 31545 10 +23009 31160 7 +12430 8634 7 +25074 41507 11 +59003 43564 13 +58798 22094 13 +12924 10459 7 +39116 35684 9 +38496 39292 10 +39557 50676 9 +4653 24491 2 +23421 2294 10 +8621 45370 15 +46419 30879 14 +12641 45229 8 +16300 1025 9 +18537 33988 14 +2464 16068 6 +12527 34883 11 +9933 8363 18 +26046 28168 11 +2892 54527 4 +8451 47356 4 +33077 47669 8 +23626 34062 8 +15071 3096 11 +8534 4868 7 +29633 42242 8 +5256 22099 9 +21038 53717 9 +59299 17704 4 +33603 48276 11 +37173 23335 8 +22894 42458 12 +5858 23746 8 +37648 37404 7 +39319 57423 18 +7908 35285 9 +59920 25154 6 +22916 28506 9 +43254 11527 11 +41135 1823 11 +49804 54033 10 +22580 43883 7 +30140 35361 8 +51388 52150 9 +12319 34572 10 +14330 56132 13 +20374 7806 6 +19769 12994 7 +41168 23655 12 +31122 8050 1 +34639 37484 2 +11668 32789 9 +9671 27907 8 +6519 48012 4 +8577 59695 15 +8994 44396 15 +29858 51450 16 +58285 45595 8 +13984 15391 4 +1472 11135 2 +30795 21056 7 +29912 4513 9 +18183 26196 12 +54301 57436 4 +16878 51332 12 +31193 48434 6 +3427 53995 4 +27447 18982 14 +54047 13070 13 +10202 32758 12 +37068 48944 14 +52014 5098 9 +32476 47352 6 +57786 1790 17 +51466 24191 6 +57345 43122 7 +22162 27330 4 +56847 32063 3 +43020 23134 1 +15253 19803 12 +16533 3418 6 +50490 7781 16 +25289 20827 2 +58415 44594 10 +21869 59778 12 +59404 7539 17 +56792 51416 14 +28743 9840 1 +3001 3868 7 +12954 29357 5 +23221 28139 7 +1288 22476 6 +15107 29353 5 +32938 55388 11 +880 10406 9 +45043 54278 10 +21177 6344 10 +16166 43161 8 +18030 23165 6 +25541 1728 15 +54898 8992 4 +20362 8550 4 +52778 21550 10 +20137 42784 13 +20000 15216 8 +10883 20966 17 +9753 5186 3 +32691 9732 11 +10139 2102 8 +56368 18479 12 +17811 4816 14 +57790 44590 9 +2832 12827 8 +49225 24999 17 +31050 10868 5 +47676 51766 10 +52087 13854 4 +20678 3242 3 +39013 2431 14 +7512 22482 12 +56583 23286 6 +27505 22627 7 +28870 22492 9 +33771 19762 14 +25782 13616 16 +10954 44341 10 +40236 15336 7 +57861 30210 5 +11275 44277 2 +23203 1899 8 +55783 59385 18 +53482 1548 4 +47292 31002 11 +55147 14831 15 +12617 45810 12 +11551 33306 10 +46155 21415 10 +33208 47742 6 +39648 22107 15 +19751 49805 3 +20812 1008 12 +42814 24139 3 +6285 58712 13 +22461 33814 10 +27884 34264 10 +23341 56577 14 +5340 48345 5 +2750 56404 7 +36785 752 11 +18047 24825 17 +56425 56330 13 +52432 5732 4 +18118 27003 10 +5364 54274 13 +49879 10839 15 +23801 16930 5 +33930 40573 6 +5333 9862 10 +12491 41536 8 +49309 58747 7 +54876 8841 3 +5714 25003 2 +9602 29891 9 +30150 14484 8 +37768 6237 13 +13617 2313 6 +6779 41727 12 +32754 8559 13 +13663 54948 11 +39270 33315 8 +21796 16368 3 +13185 49463 5 +55980 23283 12 +24826 3286 8 +17708 24116 11 +15423 1932 5 +8399 34406 8 +50477 8744 6 +51647 8242 17 +7059 4074 14 +49195 12012 7 +54681 13818 9 +58598 27646 14 +1023 1070 13 +972 26697 14 +19362 41965 10 +2330 55230 11 +12178 54514 1 +41065 39803 14 +9875 28684 3 +55064 2136 10 +31459 57072 16 +45286 8912 8 +28594 59908 13 +811 18832 3 +21457 32170 10 +29395 3095 9 +14790 50271 11 +39166 46308 18 +9169 55532 6 +15076 48902 4 +19687 37255 17 +40813 47087 0 +27140 52216 10 +7592 41112 7 +22420 19502 9 +37964 50270 8 +19925 39278 11 +27691 56467 5 +19688 13221 5 +56251 20043 13 +7672 40866 6 +11378 40554 10 +38432 16251 5 +9176 38074 17 +37865 32532 14 +56840 5596 13 +29519 34773 2 +3264 27832 7 +3526 7852 15 +18575 16788 12 +5054 53724 4 +41752 48808 5 +4480 31592 6 +13058 50325 12 +35625 41428 10 +50788 30179 2 +56741 37583 10 +13280 48657 8 +13223 16837 6 +58462 46372 1 +29968 14047 5 +37647 8617 2 +16016 45691 14 +20889 51123 17 +54647 47644 10 +37588 10030 7 +16774 59463 9 +47161 51042 16 +22971 43919 14 +56666 7256 14 +54429 57010 11 +32075 16770 11 +16164 40739 8 +14936 22248 2 +21933 12329 3 +40180 42071 1 +13743 38900 5 +10556 17573 5 +15985 36864 7 +31276 32835 9 +10971 31096 3 +50594 9611 14 +19498 22603 4 +55877 58960 12 +7751 16397 8 +28135 49570 5 +18188 54756 3 +45034 50121 16 +40021 20510 5 +49019 19948 14 +56130 41948 15 +33569 30216 13 +23450 49440 7 +42414 57744 14 +42759 409 9 +31261 34499 15 +21846 24890 9 +7142 17652 14 +48606 19061 5 +55041 34438 12 +32489 3171 3 +35663 50083 1 +17829 43066 11 +48510 30495 8 +18957 33609 9 +30273 4444 3 +49061 7094 14 +24261 59868 8 +25779 26680 6 +28404 24102 3 +58741 40135 5 +31162 59417 14 +58306 17035 1 +3143 33996 7 +42642 48005 15 +17604 40663 11 +32441 49618 15 +13371 36569 0 +51880 42132 9 +46693 11006 7 +9243 26483 13 +30732 38329 15 +9117 265 16 +36809 49522 8 +40911 55810 11 +32979 18617 5 +44401 49414 10 +18216 27481 9 +8784 9574 8 +2800 1018 4 +25458 8222 8 +59234 34753 14 +45615 55255 13 +11692 36693 6 +25987 49285 2 +28399 17989 16 +15558 48927 14 +10423 6078 12 +55046 25180 5 +45051 55350 7 +21777 6794 8 +17620 11939 1 +21510 48519 16 +35642 10365 2 +19540 2902 12 +14660 34851 8 +18538 59681 0 +57157 44031 7 +9219 56881 16 +9037 12563 12 +51220 18870 7 +22385 40340 6 +36879 31145 2 +45049 4075 9 +43779 50221 3 +2895 45206 5 +24320 49007 9 +570 31282 3 +7992 33252 16 +28750 59119 12 +44122 15312 17 +48590 25757 6 +57364 33615 6 +2811 9587 6 +42211 14304 15 +31433 55461 7 +58116 17110 2 +57409 27042 11 +46019 6110 6 +27599 28062 17 +31941 39241 8 +18375 46839 12 +2901 41426 12 +27664 29162 10 +46864 16412 8 +12294 22799 18 +12917 52851 7 +20938 46159 9 +40969 42137 3 +26983 10502 8 +15825 39585 8 +58284 38797 12 +11856 1808 6 +47206 17231 11 +15754 50630 7 +27741 20820 12 +3685 53803 8 +48373 12337 4 +46343 53299 2 +46857 40830 6 +48288 35293 8 +46437 51883 1 +24051 9159 13 +6292 30791 2 +44272 9632 12 +3323 52879 10 +27994 16422 17 +54077 43487 7 +48821 15628 6 +17616 26074 10 +882 6806 12 +14769 36423 6 +26559 21860 7 +46050 54038 11 +30261 44735 7 +31471 57869 12 +57747 56656 5 +17077 17376 3 +10835 21670 9 +7736 25168 11 +39220 37496 4 +15852 8007 6 +51299 25731 8 +57735 47421 11 +19484 15145 10 +27661 6244 10 +29216 50679 9 +7734 6449 8 +22722 39776 5 +30188 35240 9 +14474 8614 10 +29549 18937 8 +19953 43464 17 +33568 47121 7 +4084 29160 14 +44700 22421 8 +5528 26436 2 +14121 50090 6 +12765 55260 5 +10981 33391 12 +59376 44481 9 +7347 53378 6 +50511 13318 6 +58077 59212 8 +32828 55895 12 +36515 59408 6 +48031 55624 3 +36216 44365 9 +27237 56581 12 +44807 10882 10 +33662 49919 3 +30807 43400 7 +48428 53916 8 +1963 4896 4 +36609 31826 12 +49629 22401 11 +28457 52055 9 +24593 37716 10 +22444 43980 1 +20420 16461 2 +50564 32664 7 +53231 45333 10 +34834 22814 15 +53766 56861 16 +25240 39860 7 +11942 46325 12 +4720 1566 12 +2667 54766 10 +10115 20359 13 +14908 5260 14 +38439 15688 7 +34452 29037 13 +20195 6718 2 +2698 47009 14 +39309 45658 3 +19955 19994 6 +3431 26787 6 +26299 6694 15 +379 49612 5 +30691 50156 4 +7279 58686 11 +4406 6003 5 +57699 39042 11 +27480 57108 11 +20058 42281 8 +28938 30458 8 +54138 13470 10 +9358 7537 10 +56522 22526 8 +55295 30692 12 +6455 20393 8 +13054 21877 3 +37164 25489 11 +27043 7822 14 +4432 14553 15 +31850 17260 8 +3984 42835 4 +46621 14216 12 +49103 38739 8 +10595 9528 16 +31832 33851 15 +651 41672 9 +14006 44007 13 +8327 41633 10 +223 23004 15 +3077 6701 3 +12193 49247 2 +52188 36865 10 +4838 45118 9 +39491 23155 11 +40999 55772 9 +56751 27928 10 +56962 20346 9 +23093 31265 1 +26770 8151 8 +50888 13644 13 +13183 4066 5 +47263 8454 6 +49712 5536 12 +39903 30959 12 +41864 41679 12 +31286 40442 8 +24235 56535 8 +16338 46652 7 +15490 45772 15 +42524 52788 15 +6064 20853 12 +294 27315 8 +9148 58003 8 +28367 53484 2 +38682 37224 1 +5900 38969 11 +46835 50108 8 +47425 32058 14 +51397 3811 2 +27787 13580 7 +4514 41131 9 +13085 46402 10 +50929 38113 5 +24780 12911 5 +33211 12590 10 +2668 23756 9 +26765 47179 12 +1463 39658 9 +44615 27275 14 +15650 46520 3 +53471 51319 7 +26599 11943 5 +59470 33086 7 +49386 46810 9 +16203 35024 10 +37773 55765 9 +8986 10946 12 +18135 6627 4 +22422 7086 12 +13474 39478 9 +33783 654 16 +23110 50149 10 +41081 30360 18 +33174 1461 13 +12608 27548 4 +37575 22596 9 +33316 5084 9 +27833 10694 14 +35728 24222 8 +10201 21599 14 +25938 39927 13 +13245 35895 10 +37712 44741 13 +26651 3375 4 +38359 51750 3 +27262 6529 6 +40189 39364 6 +15480 29865 9 +7472 46559 7 +4591 36191 11 +21954 4092 9 +44693 1443 1 +51808 48137 5 +39285 27568 11 +42062 13876 15 +36283 36842 7 +36460 16561 11 +30483 15898 4 +29463 34901 15 +43804 50566 6 +37021 26096 4 +45851 54067 12 +58391 40736 10 +12298 27989 10 +41076 48384 10 +22217 13643 3 +13057 14475 16 +28544 26280 4 +27944 5104 9 +9567 43293 10 +5585 36297 1 +20258 6299 7 +51440 13035 14 +1813 8478 11 +23768 18328 14 +25350 25677 9 +50297 20892 9 +28495 29425 10 +19933 27458 11 +21808 31272 6 +55611 55568 17 +49542 14375 5 +18765 55546 7 +4978 15146 10 +59276 7969 7 +30933 38518 8 +47607 36786 5 +12895 13457 8 +1785 7337 7 +4315 32687 16 +54622 52425 11 +4814 29442 12 +26305 37696 5 +41566 28204 8 +45478 11293 15 +2315 31707 12 +16862 15846 7 +2599 13091 8 +4199 4905 9 +7106 35830 7 +40146 46143 10 +29247 30011 5 +18996 12704 10 +55200 22691 9 +45047 37314 5 +21830 27468 11 +50586 43376 2 +47429 49266 9 +55062 48072 12 +19512 11322 17 +29163 54932 11 +6426 31154 5 +12163 56783 9 +31574 57163 6 +5116 54239 9 +36797 34715 9 +42097 1205 10 +32746 14950 9 +11934 691 10 +28491 4767 13 +23821 29551 1 +3257 37937 9 +20312 13602 12 +21378 40199 9 +27130 51004 16 +58050 12700 9 +14620 43522 12 +4940 39844 9 +57268 28472 4 +45267 29654 8 +7420 28534 12 +29955 14924 6 +27359 21747 8 +20251 44932 10 +7226 15013 9 +3938 32811 6 +38720 4876 9 +53161 52450 9 +28682 13454 8 +22747 30765 8 +59697 17005 2 +3693 16280 9 +20138 14957 13 +39564 53956 7 +1412 30076 9 +34464 38558 5 +28905 26425 12 +25262 10358 16 +29531 494 14 +19037 55072 15 +7648 42010 0 +18915 25631 6 +13370 20296 9 +31570 24195 5 +45437 50714 9 +35690 30348 9 +21728 7644 13 +25462 22054 14 +24794 2785 8 +3572 29748 11 +37391 47131 11 +10189 20165 10 +4885 13710 12 +40871 48251 11 +39699 36844 3 +53573 18567 2 +32920 26056 14 +18316 5171 3 +21317 11504 10 +6170 13682 11 +53509 57472 3 +15295 43757 6 +39494 58511 1 +6822 5445 5 +1935 52403 5 +4255 16843 14 +777 29498 8 +40726 19672 12 +20363 19340 12 +35456 36098 3 +38095 7571 7 +17871 47037 6 +11496 30747 7 +7840 331 11 +3056 33124 5 +54085 55229 14 +29263 43342 8 +21282 15003 11 +12367 20769 6 +55593 49929 2 +42787 48233 7 +28448 24729 10 +38672 43382 14 +53880 51370 6 +20245 45156 14 +6073 36673 15 +553 33532 4 +30465 37719 8 +51200 36164 10 +51991 26608 3 +15630 46780 4 +54717 2272 11 +9120 8759 14 +39879 47805 6 +58757 17887 12 +59599 34898 7 +15106 14643 14 +24059 35365 11 +46271 25640 18 +39983 58896 6 +37371 31087 14 +56621 32022 5 +39606 58161 1 +48000 44502 6 +23386 40019 13 +24980 17838 4 +44752 24615 5 +26001 41546 13 +47448 7447 11 +2332 36761 5 +35061 52057 13 +5983 57826 9 +54384 45894 6 +33283 18051 12 +46098 28409 6 +21892 5437 16 +38393 12292 13 +20652 50678 5 +21432 23725 13 +4773 54223 1 +51467 12695 13 +31804 11087 15 +30473 55583 1 +1874 2066 2 +15096 27082 8 +35641 55734 14 +961 14458 3 +38958 30156 6 +44073 6318 7 +28067 27608 10 +18714 47004 9 +59926 15249 8 +44299 13542 9 +59538 29959 14 +23624 45303 9 +23022 55711 12 +9013 46761 5 +36233 12436 9 +3244 30370 2 +32086 46137 9 +49308 50852 1 +19316 33887 12 +43447 12510 9 +11157 48042 10 +56634 55301 12 +8804 45993 9 +37462 23197 6 +36115 39604 15 +5995 12511 14 +28742 29787 13 +18480 14222 11 +44706 40536 7 +34087 40835 6 +17746 28178 9 +2962 16656 5 +17449 14612 1 +36289 26751 7 +46672 8694 15 +31441 34241 9 +33885 23427 14 +38915 15361 7 +53845 16105 9 +39970 11486 7 +38568 12365 5 +18854 2948 9 +45549 35702 11 +40317 36038 15 +55477 54779 14 +26141 58016 13 +14494 29048 14 +27266 36801 7 +59298 5068 9 +53771 3912 16 +19618 17803 16 +52741 40057 6 +374 22728 12 +16316 59448 13 +11647 50634 17 +37940 56798 10 +48707 39608 14 +58899 14634 13 +31866 19060 9 +25131 38887 17 +13492 11123 9 +3265 18180 13 +4374 6926 1 +23748 27990 9 +10713 35828 7 +1390 22197 6 +19435 24432 12 +34729 42001 11 +15992 58132 9 +4237 13021 6 +33506 48878 11 +54584 16536 10 +44258 56112 13 +4832 11665 10 +55139 52166 10 +39111 22706 9 +19152 17672 10 +42821 44309 8 +3894 52003 12 +31300 22989 10 +37223 58669 9 +46389 23731 9 +15306 8923 8 +15546 45004 15 +33153 23782 14 +40627 31072 16 +45192 11620 7 +40706 33132 11 +26020 6149 14 +35596 58133 7 +18384 21644 5 +59630 36092 7 +4366 53258 14 +47333 3936 7 +8789 45561 7 +29910 705 12 +47139 27431 5 +14747 30962 9 +6462 40752 7 +56303 59832 10 +52832 22367 4 +10332 9964 8 +29058 38960 9 +22576 59646 16 +37540 31695 3 +21779 23547 8 +8718 38834 11 +39874 57589 4 +2227 54254 2 +50801 28711 10 +15927 27630 5 +22510 50528 9 +45116 23668 13 +37926 15794 6 +15292 27703 9 +38941 19192 5 +44833 36013 17 +32542 37253 15 +2398 59271 12 +17007 42749 15 +42068 38331 10 +55825 54774 6 +24096 33908 5 +2836 34132 13 +25902 54657 6 +48749 21578 14 +39890 10723 2 +16710 31924 13 +40689 47963 14 +53374 57443 7 +28981 47920 6 +42764 53552 5 +40525 43137 5 +52276 30699 0 +14089 9472 2 +35958 56805 14 +3857 38552 13 +3644 39863 8 +44106 17343 12 +40400 57226 6 +33149 41371 0 +198 57931 4 +22681 58543 14 +1423 4741 6 +13291 1194 13 +16120 12217 5 +44405 11682 13 +14650 15261 7 +35120 1821 15 +32818 18444 3 +5895 10641 6 +14868 39695 3 +29515 38927 3 +7527 12202 16 +17026 49402 8 +48768 9434 14 +3029 6314 12 +33632 41342 9 +41407 19722 9 +19479 12019 11 +52542 23077 14 +3340 49906 11 +8168 26664 15 +35968 35043 9 +8104 32049 9 +58680 22649 15 +41583 42818 9 +33577 7823 3 +15189 42332 1 +47929 46344 7 +36662 46338 10 +18269 59975 11 +12742 59924 13 +56696 19415 3 +37194 9427 9 +57564 7075 8 +43745 43242 16 +45401 17248 7 +25701 48174 3 +27144 28065 15 +37034 49898 16 +8127 21915 16 +37833 3031 12 +46443 17839 1 +13011 39625 11 +3111 58022 2 +552 36502 5 +2157 41174 11 +36556 1065 6 +18918 53320 7 +50446 1408 6 +35259 21476 5 +58292 33835 7 +29812 36627 9 +11768 14233 12 +50445 56274 16 +9399 57899 3 +18182 7807 1 +41547 7666 9 +5852 25601 6 +7849 4750 8 +51774 1199 2 +7853 10918 13 +8530 6566 8 +52391 22625 10 +25569 20779 3 +52295 49762 7 +5280 17894 15 +42649 16091 3 +17547 40443 9 +53377 59125 8 +12766 57035 6 +6081 32234 6 +48912 2004 4 +26993 55793 5 +30676 13025 6 +45258 13731 13 +41907 50654 0 +54166 55410 9 +30224 7012 7 +47687 20125 11 +7222 53492 5 +23057 1124 11 +35887 33422 11 +34424 47590 6 +3147 12449 7 +33267 49264 7 +11555 34380 14 +17960 35785 3 +41148 4963 13 +40649 38214 6 +10357 4892 7 +24810 43982 13 +36333 35774 2 +10791 22811 7 +36732 30971 9 +44204 28852 13 +12720 23021 10 +20482 27827 7 +32336 19822 0 +49423 25431 7 +28196 7745 4 +25627 15319 9 +30627 23226 14 +42327 17181 11 +35922 43265 3 +53385 1863 6 +28849 41278 12 +52687 31056 9 +328 10942 9 +51867 36088 8 +59303 42753 13 +47360 4133 5 +21363 52034 13 +4348 29785 11 +16996 14810 7 +55021 47378 9 +29681 28434 7 +8509 30587 1 +33485 16967 9 +54155 398 8 +47934 35257 6 +20538 16177 6 +25991 25453 5 +4423 6436 5 +12410 28253 10 +27239 16358 7 +17594 31634 10 +58371 53802 13 +17870 4992 12 +27551 34885 11 +438 45114 11 +35451 24697 10 +8126 45019 13 +27642 17358 14 +14143 4369 8 +24594 55079 16 +42873 7528 10 +34012 12733 11 +51090 17603 2 +56392 17478 11 +40804 8954 16 +43364 39621 13 +47391 10714 3 +59511 24930 9 +22435 14496 10 +44554 59029 11 +2955 43401 7 +55106 3261 7 +8103 13384 7 +3555 33503 9 +25867 51141 10 +57908 23031 6 +53784 31936 12 +22918 3847 14 +55320 33099 7 +30365 47459 11 +410 57360 8 +33852 57383 9 +5106 5386 18 +7344 59383 5 +35986 12944 11 +19492 9470 7 +38310 28037 3 +42362 44529 1 +54196 25834 12 +48382 17897 15 +20616 55199 5 +54462 58271 12 +46712 13599 11 +5996 18208 6 +3599 21721 7 +42024 12763 7 +8899 27273 18 +13294 51506 5 +26988 58056 7 +42292 33687 7 +10649 11941 14 +31158 5363 10 +47405 10775 3 +42167 51588 12 +47211 6629 4 +50105 48423 4 +44240 4442 5 +7283 18309 10 +52578 29923 15 +29406 24272 13 +8063 52083 3 +51595 19896 15 +39602 6062 9 +54785 44775 12 +48357 16271 11 +1407 6954 8 +17627 17185 8 +1665 12564 5 +18695 213 3 +47876 25285 3 +3060 47108 8 +23525 44041 10 +54650 16220 7 +48790 59130 2 +31435 40254 8 +21861 35588 9 +57336 59580 7 +31944 59575 7 +15024 23444 6 +39599 57620 10 +15729 7470 11 +3532 31566 10 +46274 24141 14 +2371 8537 12 +46929 11493 11 +27984 54362 15 +54884 34706 8 +29159 5586 13 +24316 33828 7 +11192 44662 14 +3793 57807 9 +15176 25538 6 +58725 1997 12 +12502 38595 6 +53878 56369 10 +21272 27455 2 +49763 33837 6 +19578 50895 10 +57553 25258 14 +12902 31478 7 +3188 26942 8 +30968 29218 10 +36121 54547 14 +45570 42085 12 +20785 47877 14 +7933 39838 3 +15186 19809 10 +7520 27666 5 +42788 16731 15 +21212 43769 10 +41947 41003 11 +8891 50483 8 +11101 47118 9 +31513 32906 9 +15660 11701 2 +22552 236 14 +44659 3463 15 +44197 356 9 +16156 3196 11 +23213 31524 10 +28586 3679 3 +9231 58017 3 +51101 46803 6 +22668 41844 10 +34167 40556 4 +9937 56611 15 +1450 26401 2 +14626 42700 14 +41674 16476 14 +51262 22138 6 +28798 40852 14 +17995 13203 2 +28762 25497 5 +5926 41810 3 +8226 45843 5 +34139 59301 10 +56499 16550 11 +3011 24448 11 +29117 13536 13 +38609 2128 5 +14114 57514 13 +27332 41526 1 +6674 51556 5 +9851 2433 10 +20776 20003 7 +39673 25158 7 +37544 15385 7 +26789 26157 3 +43589 59327 8 +16172 40073 17 +55999 40174 12 +23068 16212 14 +10661 7928 13 +59978 47535 4 +6969 29055 9 +10221 50616 4 +36035 31240 11 +59183 6461 8 +26273 34053 9 +10061 58903 9 +46 16716 10 +59138 49521 8 +16894 42961 14 +50545 2318 4 +46192 37979 8 +49779 20956 10 +16141 25725 8 +6466 47740 2 +42060 7257 10 +12775 57560 10 +51980 611 7 +963 25271 14 +1233 2107 6 +57757 6138 2 +28086 49856 6 +32414 5917 11 +37950 7356 8 +25490 21381 7 +6437 48201 15 +12739 44875 17 +10404 39077 2 +24997 59658 3 +14038 34990 2 +18811 27508 16 +36026 27919 9 +47726 48333 15 +743 39460 5 +816 15120 6 +38488 59526 7 +46301 21958 10 +14667 21116 12 +3018 54640 9 +39747 10492 11 +33857 29751 10 +51104 40742 15 +57005 34867 1 +11699 32054 7 +26834 56362 9 +41300 20501 14 +30346 58179 11 +5422 9586 11 +8695 34586 4 +25107 50200 3 +39326 56765 5 +44873 46673 10 +39624 12169 4 +30205 41802 11 +57260 29018 15 +3406 1386 1 +5208 7569 12 +17941 19375 4 +8727 6707 9 +33648 6810 5 +26023 25435 14 +51422 21680 1 +36259 19504 6 +16988 40990 5 +25795 8106 7 +47600 41913 11 +54252 59998 12 +58781 20263 7 +24711 19630 2 +14802 37208 13 +20428 18611 11 +15060 40976 1 +36268 15034 6 +34149 45251 9 +1800 37545 4 +57077 54477 15 +6588 54341 17 +13133 21137 6 +26890 54522 11 +2500 57806 3 +30621 36316 15 +51610 56803 5 +6435 155 13 +16924 49326 4 +20549 49073 15 +46061 27807 9 +33361 55342 7 +55155 15233 4 +21663 47685 10 +43880 2881 15 +3036 9278 9 +28593 26592 5 +56721 40002 3 +32717 13514 9 +17703 22952 8 +47318 10866 12 +50263 26276 14 +16035 1553 15 +52899 42751 14 +42065 596 2 +51237 52180 12 +3266 49190 10 +5494 4862 9 +40901 15703 7 +50245 16030 11 +42590 13261 11 +13565 42685 12 +55406 30644 12 +57234 19892 10 +58040 55228 7 +19292 32377 9 +52333 36189 12 +10004 41408 15 +57700 19024 9 +23924 46812 6 +51650 56599 16 +19743 15459 15 +3953 15656 3 +29655 44790 15 +2438 9927 16 +13240 44235 5 +2580 36085 4 +37925 5773 2 +47860 19946 6 +28286 53150 8 +46545 55088 16 +36388 48220 3 +46046 38287 6 +43669 46328 7 +43465 16769 6 +10934 41111 15 +53869 53619 9 +29514 15820 9 +43362 9688 7 +10129 3367 1 +23166 30356 11 +56884 55681 9 +52698 32437 2 +49127 54269 5 +14073 34610 12 +12478 28815 8 +37554 15491 0 +21676 28547 15 +30035 43074 1 +53545 20068 11 +47846 316 10 +25322 10777 6 +8890 8465 12 +18893 28927 9 +46651 38985 10 +52142 9924 10 +1848 51094 15 +44324 57563 10 +31105 57968 7 +17362 50299 12 +48759 5847 12 +109 11436 4 +27344 51168 18 +36763 54499 10 +30227 36851 3 +34171 29897 4 +14054 433 8 +44134 23656 4 +52726 2568 5 +17482 30942 11 +37241 18935 11 +59901 5905 0 +32558 13965 7 +44011 33912 13 +17088 12689 8 +22255 47718 10 +48471 42229 14 +22768 56148 10 +16760 41900 4 +57825 20610 10 +43713 9540 5 +31793 59645 5 +40822 57282 14 +4870 1249 2 +54535 16419 10 +56944 46702 12 +55654 25408 4 +39679 47710 8 +49961 34560 8 +40211 40797 7 +50942 42773 16 +13635 43900 14 +7903 8873 5 +33072 5438 10 +59307 40677 7 +9791 21758 16 +43350 1471 1 +17643 15772 11 +45962 20441 3 +54219 36126 12 +32866 17022 7 +9883 1573 6 +50407 16342 9 +50621 31603 3 +7628 813 4 +31187 21092 10 +1395 3557 4 +36749 9362 4 +27931 40965 0 +59467 22829 3 +23397 59712 2 +49815 40359 1 +11052 11361 0 +46492 22992 13 +32534 22536 4 +41130 17441 15 +9333 7266 4 +17002 8100 15 +38103 53493 3 +39377 24958 10 +33630 831 12 +30563 8125 14 +9745 16589 10 +53030 30622 5 +41911 45110 10 +47965 39788 2 +28673 14213 6 +43994 28201 9 +51040 49825 10 +11558 40720 4 +35373 31338 4 +829 51887 11 +48678 8010 12 +28855 49341 4 +30881 37533 4 +29151 43115 6 +33974 41748 10 +13641 13790 1 +50199 29294 9 +39016 56041 18 +17693 24307 3 +31302 13072 14 +1913 42599 5 +7770 32627 9 +891 37651 10 +9853 22426 7 +55687 51149 5 +28899 21081 11 +12520 32648 15 +48722 33372 12 +39690 15351 10 +46368 49637 16 +29377 47896 9 +34784 51866 4 +27142 36398 8 +4910 17734 9 +41445 38149 7 +54708 45182 2 +23100 54405 16 +23548 25670 13 +1614 15266 3 +12140 51451 1 +33428 44332 5 +30830 32448 8 +19978 41653 10 +31461 10483 11 +57905 23845 7 +57038 22664 17 +17675 11390 14 +32780 21483 9 +2320 10180 7 +27573 47852 10 +52479 24782 4 +41192 36642 9 +9928 360 8 +22474 46666 6 +33728 46384 10 +16765 54525 9 +34324 29169 12 +20624 24081 2 +20065 40160 4 +34576 21364 8 +7460 56695 11 +5138 25160 11 +40888 31611 8 +20434 1421 18 +57982 51907 13 +22744 44673 5 +11150 5067 12 +35683 53812 11 +9373 35444 16 +43690 33022 11 +41224 21186 11 +31336 6961 18 +26468 33627 9 +29675 362 12 +26648 27722 12 +48894 34069 16 +46681 43475 6 +15441 6324 11 +24908 26126 11 +50196 52070 10 +49267 33345 2 +6035 35858 9 +40136 21353 9 +27152 17920 8 +53223 9889 12 +43870 50074 17 +48132 6547 7 +22304 43410 11 +10355 33312 10 +55107 49890 13 +37803 99 7 +45930 22736 12 +21982 16500 10 +34226 24290 4 +1605 43616 1 +5218 31783 15 +55137 15452 9 +9104 58602 5 +40762 13698 18 +853 15220 13 +35719 48068 5 +53751 8589 6 +43585 45355 14 +26901 14282 5 +28997 14517 8 +39545 20871 11 +8948 4851 5 +59300 4257 7 +472 11737 4 +9618 16513 6 +52498 24820 6 +24526 50555 14 +53538 2123 6 +32512 18938 9 +30869 20629 3 +47372 25822 1 +17504 39025 14 +1234 4452 10 +31238 31597 2 +11850 13982 14 +15274 13377 4 +58588 56354 8 +10740 33490 13 +51582 57320 14 +48847 58278 8 +58084 19715 12 +17202 57873 6 +31846 14050 3 +25152 13511 6 +51254 26422 5 +57505 37660 3 +49610 11023 5 +16634 53873 4 +29100 3124 8 +225 6709 9 +57090 39876 16 +2520 11317 5 +30075 52370 4 +24779 53184 14 +25272 38111 6 +19352 3131 7 +19568 28885 9 +32698 19320 14 +20151 31736 11 +40043 6433 6 +47936 41940 14 +6172 39800 2 +10567 26318 8 +57375 23290 5 +47435 23809 1 +33362 14760 9 +21983 33757 11 +32965 2916 13 +54507 51773 13 +32682 20067 7 +29236 58188 16 +44057 32911 10 +5554 37043 6 +30697 51627 5 +52549 50824 5 +10795 5448 14 +57270 30620 11 +6804 14203 12 +17451 48761 7 +42373 30238 3 +4991 4028 9 +14680 16700 16 +50693 59001 6 +37787 33645 0 +34877 2859 9 +27319 39433 10 +31110 14336 15 +24361 5339 14 +4719 31317 7 +53728 57439 10 +53046 25947 13 +24218 37009 12 +45106 49687 13 +49959 9035 6 +46498 55658 8 +48968 57277 17 +6012 23419 5 +56951 18808 9 +29245 19878 4 +48550 2430 5 +16526 9643 5 +3967 1540 15 +17661 2247 10 +31790 58449 7 +40563 26304 7 +46120 6416 9 +9295 47420 14 +28055 19799 15 +44859 3275 5 +49183 1724 5 +49157 42886 6 +19868 35290 7 +41208 59081 8 +37347 7995 10 +2492 4627 16 +13172 32046 14 +48709 3690 15 +1489 42918 2 +39352 20088 1 +30408 49799 8 +39090 40884 3 +40319 33028 4 +22108 58785 12 +28621 47363 11 +47545 8388 2 +7630 23872 2 +5607 40727 17 +22848 43739 4 +21060 37055 8 +28188 30722 15 +59115 25142 13 +23689 17354 8 +31388 55840 2 +50692 49936 10 +50171 4608 8 +30541 39207 7 +52536 41919 15 +4188 9129 15 +36976 21584 7 +21514 29533 16 +14008 50008 16 +51869 238 8 +18034 51534 9 +22083 20395 4 +53850 30844 12 +25366 21893 3 +7705 56582 10 +31677 30859 3 +702 5419 6 +55926 2695 4 +22676 12376 9 +45095 22689 5 +11526 51527 9 +49855 14861 3 +7605 34093 11 +926 30398 7 +15952 5323 10 +10845 4739 9 +42954 12091 5 +58079 21805 11 +4173 39711 8 +41202 8497 11 +44389 10870 5 +58255 45546 6 +20232 27235 8 +17508 8448 9 +40354 675 7 +54523 45476 6 +27985 20185 5 +13481 36514 11 +14745 25934 9 +7808 55420 13 +13374 31347 5 +11881 54615 11 +54117 33042 8 +42246 57481 17 +44451 45076 1 +51366 50162 12 +24888 2733 3 +36778 35068 10 +50032 45021 1 +8462 36581 12 +45294 3020 15 +10832 32285 12 +23632 45215 12 +26362 51687 14 +37665 26292 7 +56221 31800 9 +55695 52338 14 +40095 6284 10 +43347 53558 3 +5107 7809 8 +17192 20305 5 +3719 304 11 +14160 19370 7 +46875 33911 10 +38523 35787 5 +4515 27532 12 +33956 30234 12 +3259 21571 9 +44176 21596 11 +15163 27913 4 +42778 54271 10 +41061 7245 16 +29476 30435 11 +49888 35661 2 +14428 36047 5 +32352 23147 16 +19357 40280 4 +1619 8961 7 +48082 488 12 +52192 12115 5 +49399 19794 11 +21537 36090 2 +40334 47723 12 +37807 52764 13 +51970 25246 5 +16579 44132 14 +46715 58106 13 +8721 48711 17 +34670 21416 12 +6378 26790 11 +2148 32812 13 +55771 37605 11 +13900 29945 15 +35261 29467 4 +19354 50309 14 +36971 46576 14 +40042 19513 9 +33247 28266 7 +53041 22628 2 +31857 22924 8 +36621 36228 4 +42315 47379 13 +23986 29866 7 +55302 39815 6 +39784 55146 15 +9468 13136 13 +52954 11331 16 +57488 26301 9 +56037 46398 7 +1185 57304 11 +53075 15774 6 +40592 18667 8 +27758 58898 16 +32556 15901 4 +50125 45272 9 +45165 53560 3 +32473 8191 14 +35447 55426 10 +58423 6723 6 +51077 20470 7 +36031 41384 0 +20972 50850 5 +57778 966 4 +27660 20444 11 +33732 4841 6 +55647 53213 14 +40679 25526 9 +1931 58128 13 +43884 7182 8 +52353 5148 8 +54949 59641 7 +2052 43972 5 +44785 7511 10 +49204 58351 18 +19564 44185 11 +19237 23991 8 +25241 16263 14 +44971 41313 14 +5817 38848 14 +48844 51352 1 +28926 52583 15 +24200 57115 7 +7099 22152 7 +38202 29503 9 +3779 2744 11 +23522 5237 9 +44178 57568 10 +11467 48795 12 +34418 9748 3 +48211 24302 6 +6855 38794 10 +9494 59899 16 +1108 31464 9 +26554 36436 10 +36322 13801 13 +27345 57385 2 +2013 24531 11 +50972 47010 16 +33734 18002 12 +26384 52415 9 +13842 57753 16 +52874 54356 2 +25287 48413 10 +22961 51148 9 +57542 39321 0 +54649 26781 3 +45940 6364 11 +16680 8820 10 +35465 34068 8 +39481 45807 16 +37006 27535 7 +42129 58572 11 +40470 7295 10 +56060 13205 11 +6309 39785 4 +23998 57238 17 +7168 5132 9 +4367 25554 13 +56788 24262 13 +16257 38940 10 +44402 39925 16 +36638 2486 11 +36080 19289 10 +17845 18603 1 +31444 38138 8 +29126 54244 17 +4796 56505 12 +8287 38124 11 +40208 33982 2 +59305 45573 13 +19421 39361 5 +58100 20472 16 +58227 15580 3 +31679 59995 9 +20376 15032 15 +37690 39654 12 +44665 39616 12 +27404 55627 12 +39214 59749 14 +44830 41860 7 +26397 28485 11 +23161 57651 11 +4078 32152 15 +50767 57573 11 +46795 41000 9 +53868 41302 18 +22659 39169 2 +3122 40529 5 +50530 51898 10 +10955 28116 14 +29328 20460 13 +37104 10809 8 +56941 20146 1 +58456 41744 6 +29574 31536 8 +22844 30929 1 +20045 19100 2 +49613 53909 12 +8512 17766 4 +8684 22687 12 +37270 28214 7 +22168 11644 6 +37402 40729 14 +47682 41964 11 +5619 14 7 +47345 56547 14 +4122 1507 18 +22732 12316 9 +39069 33638 11 +45865 11717 15 +15131 40041 14 +42261 51411 9 +57676 30281 8 +37369 52217 16 +4555 16583 15 +30582 52675 7 +49715 8500 14 +40360 22463 7 +43336 27647 8 +47976 35099 6 +45730 53347 5 +13537 47495 8 +47612 59269 7 +34727 28265 8 +21835 19092 12 +59820 10073 3 +47618 20854 8 +31577 37516 10 +28649 36381 6 +44851 33324 14 +28391 2060 12 +57734 4798 7 +26167 52060 10 +47798 2989 15 +6308 818 4 +41301 48296 10 +48129 57933 4 +55587 23966 9 +37872 56106 10 +3495 26506 12 +37701 5009 16 +39269 28494 6 +30493 58628 3 +57570 59169 11 +21207 29706 2 +33395 48453 14 +16738 53605 12 +58245 22344 9 +57544 37133 11 +16557 47443 9 +43207 4686 9 +41989 58307 1 +2223 987 11 +53061 24726 14 +57239 19628 9 +57697 53714 9 +17119 19472 14 +44845 20300 13 +53089 30957 7 +14326 11984 12 +37318 22752 9 +24199 56324 12 +53122 22630 9 +29458 47961 7 +12003 3278 9 +52139 50190 10 +45957 49295 10 +41941 2534 9 +51059 41230 5 +50543 12302 4 +3909 41971 8 +39426 46191 15 +57994 15323 15 +33788 16106 16 +51363 29782 15 +311 38511 12 +26243 17857 5 +52472 8983 8 +24210 38780 15 +4327 38866 13 +23131 58477 5 +29878 43325 18 +46617 44415 2 +25688 11759 9 +2558 19271 9 +43800 38197 8 +22357 42880 10 +9573 38049 7 +23245 3951 8 +49640 48400 14 +19784 3292 11 +18618 15132 10 +5169 12649 8 +50464 13259 8 +46806 7515 4 +41641 37893 5 +20122 5499 11 +9227 39980 2 +42701 33352 6 +11518 35651 1 +2311 48777 11 +24070 24547 5 +8548 36826 11 +10402 13507 7 +20930 57464 3 +7758 51278 7 +6771 28202 2 +53716 38876 9 +56004 53270 8 +17438 32640 3 +4817 7731 13 +29125 14133 2 +5385 9112 14 +6813 58783 11 +21904 6554 8 +4897 36034 15 +19654 35256 6 +22305 58058 17 +942 39092 15 +27557 38291 12 +32413 33614 5 +1147 11311 17 +16187 5294 12 +31399 73 14 +19422 32897 8 +3910 46884 10 +11744 11062 10 +51385 57715 6 +52794 26657 9 +8612 8827 7 +47684 31175 9 +41843 49461 6 +23933 42285 13 +23543 19347 4 +29208 52395 9 +57126 59565 12 +31699 30344 9 +44342 31069 9 +49917 21140 6 +14358 48540 17 +28623 45100 12 +27207 33309 9 +51930 42555 14 +4166 4727 9 +31810 6493 16 +39068 59077 12 +21812 45439 5 +20880 30185 16 +46066 1406 14 +33425 48190 8 +25384 53894 5 +14295 4615 5 +53742 15062 9 +57078 40890 16 +22262 12703 4 +42583 32060 7 +12310 13124 4 +15488 47809 12 +25588 21689 8 +17856 11820 10 +59883 47328 11 +2460 53366 11 +22263 31651 14 +6518 6929 14 +18919 30425 3 +25883 23267 10 +7582 39380 8 +6905 26537 9 +26504 13591 7 +43606 16222 9 +8083 10525 5 +34972 16896 13 +38854 10283 6 +58164 22104 6 +33816 7885 9 +54512 55821 4 +21936 20979 4 +42615 28836 9 +17394 49869 9 +25579 10055 15 +15149 47340 9 +7446 17467 10 +7924 20664 11 +873 16281 4 +8267 33593 9 +45647 32576 14 +12238 43766 7 +24886 28550 10 +24018 53034 6 +27324 43428 11 +59867 22456 9 +14757 1492 9 +56092 22508 14 +18069 40540 6 +46269 899 8 +12821 44952 11 +40413 19369 2 +26069 18471 5 +53958 6692 9 +32764 50945 11 +36575 7585 3 +58491 14616 7 +11315 1557 6 +8395 40384 6 +3332 32404 11 +48002 15200 15 +28639 17767 10 +57445 21697 8 +40035 16762 11 +53344 54048 9 +592 55584 12 +16655 11991 14 +14855 48147 5 +21543 9679 8 +17662 24257 7 +17345 28394 9 +14752 16041 7 +9156 53085 6 +57415 13356 12 +26952 13151 16 +46104 19025 12 +56086 21951 11 +49396 53257 6 +58236 368 17 +5327 21220 1 +21693 16427 10 +22534 30662 10 +26062 29459 8 +4127 26135 17 +24275 37358 10 +37174 5214 10 +38641 59717 15 +28873 7067 12 +58122 15594 13 +37695 28518 12 +55590 50114 14 +4912 37786 12 +52416 5179 7 +29996 59218 11 +54736 16512 6 +11688 2791 10 +56366 15252 6 +48205 1363 9 +39866 4256 7 +26022 43959 17 +3445 18678 12 +31241 56719 4 +18601 58080 7 +41129 13321 11 +24474 26639 6 +15727 53479 11 +44169 30094 9 +21128 17722 11 +29233 10322 4 +23119 40542 5 +42159 293 2 +57828 42786 8 +3903 5910 10 +58468 47306 4 +36301 1130 6 +9279 19098 12 +56454 40483 3 +11183 31202 6 +28295 19842 7 +45903 3757 9 +53644 9260 3 +12124 17974 10 +43685 43434 2 +23900 58432 10 +4650 52009 11 +37861 58248 7 +9191 52058 10 +51277 39430 7 +5818 22229 9 +35211 41344 12 +49179 30110 11 +3338 13476 16 +29693 6283 13 +37184 20281 9 +12154 7364 1 +43452 20519 13 +33786 4289 3 +20439 59140 10 +17080 13483 2 +34955 14716 13 +43164 10062 11 +52196 35344 9 +8266 55436 12 +48429 39262 10 +46556 47222 3 +57332 29512 15 +20562 35947 11 +14362 22149 11 +25491 12008 7 +34756 19223 12 +59434 31795 9 +40089 19918 9 +59981 7664 6 +48926 15244 11 +50037 5063 16 +58163 8553 7 +37079 53139 2 +10923 11789 11 +49369 41806 2 +30559 8962 12 +21059 44188 8 +13353 25383 3 +5230 6750 9 +55354 41550 8 +23325 12980 8 +56445 22100 6 +25119 44808 15 +58559 47294 4 +44005 55947 10 +110 8930 13 +9963 58497 7 +55142 33537 6 +31221 13380 9 +3094 15260 15 +18090 6672 9 +55678 11695 7 +49413 49549 16 +42212 50020 12 +58254 1225 9 +32921 5647 3 +55652 31359 13 +24945 29747 10 +630 20955 6 +29949 36819 6 +22285 16713 5 +1547 903 7 +28121 12026 12 +6632 57669 5 +11475 50893 8 +46541 9226 10 +11742 23411 4 +43562 58702 4 +1361 51849 4 +10499 23299 12 +22020 23081 13 +9353 43396 10 +221 33565 10 +50183 34382 12 +21164 59994 3 +43288 3652 11 +44748 13940 13 +43945 37229 11 +2688 37351 7 +44728 24333 9 +44168 40412 6 +13581 56744 2 +54646 38898 10 +10038 51928 14 +11960 48799 5 +38815 46770 9 +23836 20440 7 +42479 45906 10 +34891 37933 10 +46647 15867 10 +37816 24739 7 +45794 54082 12 +51784 21616 10 +25865 59486 18 +43477 31952 5 +5349 32697 12 +23384 7942 7 +55913 54041 10 +21632 53653 13 +59601 9105 8 +40707 50173 11 +57302 30778 14 +45081 41034 15 +14371 41792 10 +52606 615 15 +46658 46821 11 +58537 710 6 +56742 43956 16 +13983 11714 6 +32342 27440 18 +31294 34210 10 +27681 17156 6 +35146 51084 13 +50056 49202 6 +58395 5720 13 +49021 35020 4 +59612 44413 8 +9021 13498 10 +38458 11998 15 +2828 54682 8 +48081 6784 11 +47955 47990 7 +41805 10174 7 +18889 55650 8 +22723 5880 7 +17095 14424 4 +58767 8240 5 +22622 45418 5 +34914 31422 9 +45883 28790 12 +21825 5123 9 +46923 54679 12 +42561 59946 9 +24673 15979 14 +56405 270 7 +5397 1751 11 +42864 29623 5 +34199 28532 8 +29492 49493 17 +37945 18861 13 +50961 16181 7 +18981 49608 13 +25305 44950 2 +57297 21453 8 +23098 12246 9 +40213 15678 16 +35729 30100 7 +24058 49385 13 +33660 34964 9 +35859 57672 10 +39198 36260 2 +41622 13433 9 +48764 3 5 +11387 23919 10 +45207 56624 11 +3562 30774 3 +44028 25328 12 +42879 57689 12 +42034 52670 15 +48244 59964 12 +29083 44065 2 +54019 43504 9 +3458 32283 9 +15161 3428 11 +56371 49384 6 +22406 33 18 +53187 16457 9 +20680 22000 7 +3070 38855 5 +13994 13524 5 +35971 40355 6 +40060 35049 10 +33657 26749 7 +59878 59522 4 +23685 41201 10 +36019 5564 7 +29580 34178 16 +25544 47635 16 +31995 36497 9 +36447 32619 3 +10531 45132 5 +481 43486 6 +20268 56180 10 +43863 22778 11 +34073 8174 4 +37722 5712 9 +14646 59792 9 +18534 34441 9 +3433 57843 5 +6938 23893 14 +18829 59933 9 +55718 15224 6 +9610 58989 8 +36439 57536 6 +25752 35409 2 +28443 28449 11 +34514 10185 5 +59514 24186 16 +10095 27299 15 +25880 18553 8 +42297 54973 10 +16227 45072 5 +7422 23734 8 +53316 47517 14 +5616 26405 12 +40134 34108 16 +2331 20922 14 +14182 48551 12 +36230 52869 9 +59430 18085 11 +40367 20366 15 +45972 21198 7 +56402 22569 11 +15172 25221 9 +3683 4429 6 +7288 55001 5 +48218 41394 8 +6760 34121 14 +28043 34953 8 +51708 44135 14 +46653 59593 8 +50902 30013 16 +49097 15765 0 +53143 33509 5 +6676 11031 3 +43901 22945 10 +17289 546 11 +31557 15814 6 +45436 41378 6 +56584 7792 3 +21791 54046 5 +1382 43320 11 +23899 48328 14 +20793 23008 13 +32602 18815 6 +22351 21273 7 +9423 55536 7 +28239 58461 9 +54321 11094 14 +17794 48044 6 +21620 39477 7 +6689 5476 12 +47602 44716 6 +55890 22969 6 +44300 55557 14 +49111 27621 7 +51023 48951 9 +30086 56724 5 +54086 25303 15 +49167 20303 5 +42488 50091 5 +51398 27784 5 +49953 15077 3 +7023 23362 9 +7578 8071 10 +55984 54370 12 +31593 59390 11 +54282 12338 8 +11207 41032 12 +35839 13130 16 +45313 49082 11 +11739 939 11 +59262 6602 9 +8906 10937 8 +15370 41892 13 +29822 20965 12 +27689 44101 7 +15974 20677 10 +44157 44437 11 +40464 16465 9 +30963 18814 4 +4779 51310 10 +30571 46728 7 +6473 5306 8 +26377 22719 15 +2866 54583 8 +56380 51294 11 +30065 32944 10 +45111 1346 5 +57325 21359 10 +49278 3359 9 +7467 31412 6 +18848 46063 14 +47007 26477 5 +9691 58165 5 +55925 17585 4 +4368 2965 14 +17945 8557 5 +19768 34351 4 +46219 57263 10 +51629 26421 1 +12361 38882 5 +507 37251 5 +36624 46227 2 +7913 51537 14 +59843 59959 13 +16070 59650 15 +30683 21799 9 +5828 29907 5 +55602 42694 11 +12286 15272 4 +56257 2994 10 +2804 41888 10 +1520 23618 10 +6654 37917 1 +1260 1118 4 +45830 24701 9 +42937 48020 10 +14041 40922 1 +47196 12835 16 +30701 54140 12 +6789 15906 13 +21952 20849 5 +15092 11659 9 +14479 17555 11 +17159 6999 14 +18252 57639 8 +24144 12488 8 +15635 29441 13 +47183 27988 11 +30018 32995 15 +55784 56096 8 +31539 35238 10 +32912 14843 15 +33894 24364 11 +15460 40219 8 +39504 43162 1 +25228 58673 9 +57684 47796 2 +21155 45907 6 +36012 34543 13 +42456 25916 2 +45326 6899 10 +24295 7051 12 +8681 45292 5 +30263 19103 17 +27185 22271 11 +12195 9953 3 +14015 50787 18 +15353 42432 4 +16153 20925 10 +53530 49494 12 +39795 35462 14 +7554 24962 2 +57701 3798 15 +51789 45961 1 +20674 6331 1 +57327 10892 6 +53922 40235 14 +36334 58463 11 +47775 47415 13 +13754 32015 11 +36029 26509 11 +31432 6321 9 +31029 18022 4 +47005 23329 9 +59469 34292 16 +43476 8252 8 +33811 23467 14 +29079 24506 10 +19270 13973 8 +32962 18453 11 +15099 22193 6 +18416 39636 9 +49996 45748 0 +42667 11125 13 +711 54798 4 +12305 24073 17 +37317 51674 12 +51076 14219 11 +43530 18890 12 +3636 49313 18 +47744 59587 6 +26831 22340 12 +8165 4577 10 +5742 26701 13 +12736 9352 10 +57907 20618 8 +5620 25847 6 +42771 22308 8 +58571 15372 10 +39823 46697 7 +37240 34368 11 +30579 54954 15 +42037 29885 6 +17182 41193 5 +45617 45371 0 +24019 33635 11 +54423 7611 12 +37782 23476 7 +46813 759 11 +25503 9229 13 +41198 11950 14 +3435 42565 6 +7165 59009 7 +22071 51597 13 +32244 25592 16 +50065 41113 9 +7726 33089 12 +2831 12280 10 +48386 15766 11 +53266 36632 6 +24231 49635 10 +49933 21200 8 +40204 23938 12 +44544 19336 6 +20569 47693 5 +920 9383 3 +16200 4000 9 +35572 45646 10 +48642 56709 3 +57668 43948 9 +58168 50855 9 +55556 6740 7 +15775 18779 8 +22582 48814 6 +24623 18778 7 +40621 17683 11 +55078 31669 11 +59105 4993 1 +18031 3461 4 +23870 2199 14 +5334 12976 10 +21497 54698 9 +18901 13826 8 +50869 13328 13 +31909 41820 9 +7430 924 14 +59248 9075 7 +40286 47562 6 +54300 59693 15 +34340 18546 6 +8775 45974 5 +45876 2972 12 +31673 45473 11 +33113 42161 4 +35637 5598 12 +14849 43067 4 +29558 30355 6 +5053 33970 3 +38427 12744 8 +45768 14215 3 +1144 23559 4 +9281 42468 13 +31415 40479 5 +18186 50633 10 +4114 4576 6 +50000 47217 6 +58808 19245 7 +21246 5943 13 +26402 45240 7 +3983 14671 14 +36562 19262 7 +58988 51535 13 +54235 41893 8 +40079 48436 7 +7249 18201 7 +38255 33899 16 +2346 35631 5 +47359 14062 16 +32215 12961 14 +42235 16584 6 +32519 51589 7 +11448 11097 9 +10354 2329 7 +59056 33212 16 +52631 17968 4 +48818 33019 17 +24332 51925 5 +58945 28628 2 +9760 30768 13 +18289 28624 14 +50354 21675 6 +55268 7836 16 +14376 42552 5 +26173 30342 18 +44200 25494 13 +47665 42180 4 +9969 53506 17 +6502 50182 4 +6409 260 0 +24530 25645 7 +18036 22245 2 +23466 59553 13 +13225 4558 8 +51514 16507 12 +57702 35919 14 +58249 42381 9 +40242 39249 9 +10097 388 9 +2567 56055 5 +1612 27785 10 +4758 59207 5 +3829 10282 3 +20139 29786 7 +50110 39568 10 +7619 50537 11 +14277 30248 15 +29810 29049 6 +40068 52719 11 +13038 3034 5 +38514 12370 8 +46254 32592 7 +8739 10151 8 +18293 18143 10 +7769 18114 15 +29688 50109 8 +16873 53780 4 +27564 9426 8 +15859 18065 9 +2947 34823 10 +34513 16245 7 +16393 1640 6 +55867 42910 11 +2166 24397 2 +5367 22036 9 +19360 29562 0 +40383 59333 8 +39672 12330 10 +50891 14465 9 +36589 58820 1 +458 52523 8 +58190 57329 13 +43921 19356 14 +55912 22431 7 +4850 49093 10 +49525 53170 16 +20543 22085 10 +53152 7710 5 +25578 14423 13 +59070 23020 5 +26347 43621 10 +40580 31470 2 +14991 11356 5 +23162 35137 4 +33623 3172 7 +29289 48750 12 +30534 28452 2 +25129 44465 8 +22595 10098 5 +5700 36696 10 +45731 54934 10 +32765 16644 8 +4640 53756 14 +39125 37260 6 +36409 42597 12 +47620 49513 7 +17530 28246 9 +8648 37443 4 +50864 33641 1 +19490 56252 1 +24560 36510 12 +35536 11732 9 +43556 57132 5 +26529 38540 7 +44961 34115 13 +18223 4611 13 +47158 54956 3 +56441 42859 7 +33111 27874 2 +14314 58086 4 +37150 5756 10 +24352 12346 4 +24246 37277 15 +18377 59019 16 +9370 5610 5 +25966 4981 5 +30575 32286 9 +57468 57963 3 +40874 9259 11 +19083 30476 10 +9836 34232 9 +3321 47906 8 +42222 1860 10 +33779 5129 8 +49704 59770 14 +11581 19272 8 +39777 36742 10 +41397 25047 8 +13570 27381 15 +2684 57637 6 +5853 55065 8 +5163 53692 10 +39886 28387 5 +38584 48614 13 +12709 37221 7 +15360 7177 11 +15649 16224 2 +58516 3064 8 +46834 13582 3 +29232 40363 7 +10731 38298 11 +4334 29394 7 +11832 45846 12 +8630 54963 10 +2834 14725 4 +23260 1039 12 +23622 36086 11 +44001 26735 15 +2257 55305 5 +7025 37792 3 +41569 16182 12 +11203 30938 3 +43661 15230 16 +34507 49273 9 +7640 8622 9 +55265 33357 12 +7600 39605 10 +21986 1883 6 +39696 54419 7 +30450 35069 9 +5254 51302 13 +382 15408 9 +19764 55605 6 +12490 285 12 +58739 36513 9 +52168 49721 10 +10125 13866 11 +56470 34539 7 +59440 26553 8 +43698 22281 16 +32661 1281 11 +48117 43864 15 +43040 173 7 +12397 27008 12 +6273 36095 3 +15798 37653 0 +5819 11423 17 +29844 40253 8 +37322 15779 2 +21515 7091 8 +27293 22996 11 +10450 745 3 +33396 23781 5 +4063 57280 15 +21671 27126 13 +43466 35362 7 +36938 19207 9 +2 46599 9 +55752 7292 2 +15387 18610 18 +44112 5938 3 +21822 24668 8 +20317 46827 14 +25399 49619 9 +3010 35035 9 +50789 58528 8 +29583 18121 10 +52932 21434 14 +27817 57206 18 +52503 21424 7 +50375 3935 16 +3276 3842 15 +16491 32500 9 +32566 13714 9 +1113 40063 15 +2565 20184 11 +35292 10804 14 +44416 54134 5 +55460 36695 10 +3646 43178 13 +58387 11141 6 +8037 8137 11 +52989 35372 16 +46627 33839 8 +2234 15067 4 +3507 41027 7 +2876 49691 8 +57693 58450 7 +49153 52833 12 +58448 370 15 +20418 14723 0 +8134 50832 9 +7682 50095 15 +31572 19194 14 +7729 34587 4 +35059 26565 9 +10013 19376 4 +38562 51714 10 +23061 13689 10 +56909 22469 15 +55213 37815 10 +15002 16957 7 +1198 54141 4 +37125 9696 11 +8651 15382 7 +44804 54025 7 +59768 2248 6 +59777 41685 4 +56680 41558 14 +50726 10608 6 +4245 50640 2 +239 11026 5 +6039 3312 6 +50912 47783 15 +4760 15685 10 +283 50059 6 +50904 40717 11 +7791 15481 14 +28675 53473 9 +50335 34014 2 +40293 46296 12 +33893 37053 10 +8044 17446 12 +2797 11411 15 +4929 8310 17 +39872 59872 9 +7868 20493 8 +11749 4943 14 +47278 12636 11 +29113 22407 11 +3381 42188 4 +14252 17003 1 +29900 12254 9 +47871 59583 10 +40921 37678 1 +24793 1639 8 +23923 40959 10 +30040 22585 11 +54383 13937 9 +56596 10933 5 +8316 15987 18 +50484 48055 13 +11245 45703 10 +834 45014 11 +9755 52001 3 +15250 3826 5 +24365 27854 4 +12341 34462 7 +1814 49107 9 +11189 12464 13 +25623 51839 12 +10424 37261 3 +47466 47080 8 +4958 706 5 +10662 39469 4 +31680 43711 6 +13856 16442 9 +39020 13309 8 +29561 10390 7 +58418 53265 11 +24265 27318 0 +35696 7988 12 +35159 29082 9 +24212 23710 9 +11811 3175 2 +15973 54997 8 +46205 36404 13 +41453 2063 11 +14321 1330 3 +11875 27111 7 +54417 53749 4 +44118 5292 13 +42383 9081 17 +36774 10123 6 +4267 22487 1 +33414 51831 2 +28063 16706 5 +32918 50808 2 +58447 36909 5 +36523 44002 14 +58031 39107 15 +26632 15112 11 +57197 33561 5 +54268 37305 9 +29961 55194 4 +7209 3062 8 +39962 45380 14 +39901 1586 12 +48410 42280 6 +49556 26721 10 +39253 56250 13 +36701 32740 13 +1804 57374 17 +28482 41506 1 +35584 33191 5 +1179 42760 5 +43045 14165 0 +29650 6940 11 +14312 15043 7 +25923 44894 6 +44506 28904 5 +6962 50378 11 +37706 11775 16 +10637 34811 12 +6942 17954 12 +54018 21442 10 +46685 57498 7 +26414 8031 16 +772 39579 16 +15953 48772 13 +19030 53483 16 +2864 22065 1 +21303 6494 4 +2987 33410 14 +44206 8469 8 +25738 7095 11 +52146 3432 15 +25599 37996 9 +27866 11154 8 +30877 19898 10 +59527 20765 8 +8343 33026 8 +29301 19281 13 +50088 43373 12 +39417 16696 8 +31201 53789 3 +49882 5953 10 +24467 16949 9 +58024 25094 11 +334 59018 17 +4027 26662 3 +35415 41514 4 +35087 49200 0 +25143 28510 8 +32858 46773 9 +784 15053 11 +12344 46141 4 +20582 9991 10 +10908 3403 10 +27281 59015 8 +26024 13981 9 +4468 30167 12 +17273 40338 13 +54769 39251 10 +32959 31421 10 +46165 58560 1 +35862 44679 2 +15904 19903 2 +49455 38309 13 +37738 41937 2 +55048 57269 5 +9251 5425 2 +20860 42852 6 +17481 29725 13 +24501 12589 7 +47116 51341 16 +34008 20706 2 +49859 24329 4 +45922 9374 11 +27881 18886 8 +50857 49464 10 +2342 40630 2 +20147 49907 5 +33731 38970 7 +53216 18795 17 +13763 46288 11 +20091 1664 5 +8110 7635 3 +17199 40162 6 +40733 49451 14 +56592 25968 14 +15574 12588 6 +7118 24766 13 +15254 8141 16 +54016 57641 9 +54334 450 10 +4097 34076 7 +3643 38395 17 +53051 49880 9 +35648 14373 9 +11304 11813 3 +50706 9655 16 +41388 29657 2 +49163 53628 11 +29359 43177 11 +6365 24171 8 +9642 44718 11 +13191 6636 14 +47387 45676 8 +2097 24168 9 +49969 12547 12 +31407 39955 4 +17497 43270 13 +37121 54095 8 +55858 18638 7 +5950 1834 6 +22037 40358 14 +29042 59281 5 +49230 50649 8 +51593 58939 9 +2611 17828 8 +40457 11867 1 +30758 43701 9 +52521 27905 7 +34986 44551 8 +51679 13685 5 +12603 46226 10 +40098 24636 1 +19189 44227 1 +23301 29121 3 +27490 52767 7 +24022 21910 7 +36023 3975 5 +7008 2516 12 +40924 55816 3 +47337 11204 14 +24989 12724 10 +52683 660 11 +24435 53640 11 +2730 18332 5 +5229 40606 13 +56501 9612 9 +30796 27538 10 +25204 53665 6 +28077 20603 8 +20240 51392 7 +40730 55773 11 +52408 14094 9 +6183 28041 1 +11946 1151 10 +55728 37461 6 +50272 21252 13 +721 23342 7 +35813 5577 13 +15278 38466 3 +19992 45756 18 +12263 39824 8 +33407 34124 9 +28706 26187 7 +33985 42172 7 +55245 59855 8 +24226 32659 7 +45220 58251 7 +44015 48023 7 +41150 40116 5 +33969 56057 4 +8317 55133 7 +4623 6914 8 +9096 6579 12 +4181 24484 2 +15271 48156 7 +10690 26361 13 +29230 29777 8 +57061 7349 1 +35079 14693 6 +6702 30169 5 +52170 48034 7 +26130 24031 9 +23896 58443 10 +26589 44093 8 +35316 34300 16 +37245 26101 13 +19446 6856 4 +26667 22938 1 +44562 27423 10 +50885 39272 7 +40271 56620 10 +59563 10195 5 +55227 53225 3 +51972 10349 8 +10296 32241 13 +18235 48433 7 +7269 29486 18 +4939 15050 12 +10802 38847 3 +46567 59472 6 +50794 34136 9 +47686 16304 9 +40651 6558 2 +25775 32254 12 +23420 29388 9 +43478 46390 15 +33564 5709 12 +27516 29496 9 +27768 40895 2 +53409 56237 10 +51835 34442 4 +8019 21460 1 +25864 7591 6 +11541 34028 4 +16455 54180 9 +21574 17282 8 +31320 52447 18 +49129 50045 11 +24440 1448 4 +28504 26737 13 +13628 9952 11 +56256 10911 7 +40514 51460 13 +2939 15926 2 +33770 24039 12 +32581 21029 3 +8313 56640 15 +48326 4223 4 +48318 51536 4 +57707 2456 3 +39736 43385 15 +12198 52454 9 +54084 25929 10 +3167 39957 8 +29437 2960 9 +52246 41421 6 +4475 18093 5 +15239 33489 11 +5545 39921 4 +28181 9549 15 +29002 18839 12 +33106 46793 12 +32873 613 10 +51178 43575 9 +39316 55701 16 +19447 27026 6 +19526 26353 10 +33227 8944 10 +2444 34106 14 +35694 3885 10 +550 55545 11 +12002 42916 8 +47930 35232 11 +16176 34657 4 +30426 13695 15 +43022 56700 8 +58440 58110 1 +57675 18547 8 +20585 21768 4 +20698 20289 11 +1193 58011 16 +49710 56808 13 +52019 34748 11 +3394 324 8 +7679 22717 10 +30288 44214 14 +36015 578 11 +36430 48723 15 +54349 51443 2 +34494 28170 8 +36054 21557 10 +48364 8719 8 +55997 10297 9 +22947 36223 9 +50069 1572 6 +47576 21786 10 +7136 33148 8 +21669 3465 18 +30379 10610 8 +21722 23968 9 +38954 62 13 +16895 41528 6 +3333 54311 11 +47615 26561 11 +4201 8673 4 +41336 1197 8 +9785 53454 6 +36551 36576 9 +8154 4559 9 +52584 44330 12 +3078 35722 3 +35397 10452 11 +28072 32596 8 +53487 9023 7 +13243 32714 16 +30321 20555 10 +4833 26712 4 +30067 20356 11 +31609 25291 5 +48718 44796 9 +55829 40291 12 +1816 49876 2 +1062 59980 8 +1380 9518 6 +15552 22095 6 +50092 40164 10 +31357 48015 5 +38521 45278 11 +42974 53362 5 +3537 17972 15 +10238 58691 4 +791 5584 15 +42278 22028 6 +3299 29685 13 +12754 8216 16 +36773 7637 8 +51079 5011 8 +10715 14187 11 +7357 50638 4 +41665 57642 9 +47376 23943 6 +43121 8408 17 +14995 46305 5 +30310 39514 11 +24385 44271 13 +21696 59405 13 +29702 42443 10 +38177 22838 4 +57335 43301 11 +12033 5050 12 +16340 46811 14 +14735 34349 13 +42848 5549 4 +37954 13980 3 +51206 8747 5 +9287 4455 0 +15374 12803 7 +49741 40430 11 +42084 11835 1 +14181 14541 2 +50970 52243 12 +44633 41288 1 +43560 28745 12 +37326 30467 17 +57522 34526 6 +44835 3182 11 +56735 23479 7 +4698 49105 12 +19249 50331 4 +45806 37339 11 +27731 26655 14 +44710 47648 10 +34090 10624 10 +23475 30694 15 +43761 50176 9 +13501 20529 5 +41497 46801 10 +51757 13716 14 +585 55081 12 +13161 6002 4 +124 31742 8 +21440 15553 14 +10865 54918 7 +39789 33950 7 +11977 17932 2 +20489 28095 8 +32475 2858 3 +21962 49812 15 +6564 13402 17 +12262 55060 11 +19576 38736 10 +32129 52760 8 +3085 16952 7 +57915 33083 8 +43492 9066 12 +58728 8692 8 +37785 11645 7 +42592 50716 9 +56548 17247 11 +48102 848 11 +39104 8960 10 +8793 38306 8 +48487 9477 6 +580 17243 10 +59052 12630 9 +51742 24708 6 +12842 11915 7 +45926 11469 9 +55939 21006 3 +4044 38339 2 +48535 14144 9 +20478 32306 1 +52530 54118 8 +32136 551 7 +8735 59131 16 +46689 46459 3 +8937 36744 2 +46979 48571 11 +24926 27796 14 +21143 52721 5 +29589 25177 13 +9919 33085 7 +32763 17770 2 +54347 5939 9 +42087 46184 6 +40081 44422 5 +45978 23086 15 +38146 56807 17 +49293 43432 11 +35894 36062 18 +10005 28231 5 +22999 22184 5 +36840 29480 8 +43213 2445 12 +3192 6484 7 +1491 50831 12 +47370 37594 4 +45362 37671 4 +15078 40277 4 +43838 4062 10 +7195 13200 8 +525 48226 10 +12620 25593 8 +46003 4123 6 +49299 30417 7 +38649 4338 9 +26771 18177 11 +28757 40076 5 +49024 49790 9 +10486 38475 12 +3511 10990 13 +57248 53912 9 +3363 59095 6 +22428 34155 7 +43283 54111 5 +13823 47836 13 +16198 30911 8 +17942 19644 10 +27826 31429 6 +10160 33233 9 +29828 51620 7 +23671 3360 9 +14990 5587 10 +43166 52033 14 +4050 43563 12 +11171 39534 10 +13134 33703 3 +42019 5410 6 +27311 1560 11 +25311 50500 6 +27420 5719 8 +48420 45459 4 +11099 7750 15 +6164 29859 16 +22806 55621 7 +46898 59936 14 +39413 50178 12 +45552 23521 6 +6113 37512 8 +29197 47002 9 +56668 30825 10 +5295 14435 9 +13214 12605 0 +18077 15998 9 +40545 32210 7 +3000 46285 17 +9432 43239 11 +37189 31437 6 +13598 52625 6 +56806 12422 9 +15258 41343 11 +12000 55625 9 +21631 1319 17 +55911 39263 0 +29739 28146 8 +30147 47927 12 +42311 57283 10 +15242 16385 1 +19532 36318 6 +59490 34697 9 +42705 8428 7 +39332 53757 9 +58130 27799 11 +19678 28380 9 +21781 20265 8 +28255 20247 8 +37543 1922 4 +29056 7332 3 +10284 52271 11 +15415 43356 12 +15907 20804 8 +54365 53523 14 +10359 53275 13 +2119 33276 12 +11874 51942 12 +18975 35448 4 +29201 2180 12 +28049 35460 12 +40648 47507 4 +33826 22756 6 +42633 41103 3 +56327 38640 11 +35125 36553 11 +9923 38534 9 +24961 15337 7 +39022 39323 4 +38607 8538 8 +4840 29933 15 +18389 43775 4 +53397 22652 13 +18693 49544 11 +38700 11120 9 +23052 13143 12 +14675 23891 0 +48549 44070 8 +56632 21368 12 +19849 29167 7 +7775 1812 12 +50410 30292 9 +27685 28614 10 +19804 42047 6 +34482 36079 15 +100 54707 8 +22394 2118 11 +42945 52901 8 +48932 37398 11 +24297 3805 15 +50470 27125 7 +14029 6257 11 +31858 36354 9 +42849 52238 1 +33548 22188 8 +20737 41821 5 +35744 42933 7 +13991 59319 5 +54945 29974 7 +25156 41732 3 +37384 20197 5 +49662 19279 12 +8015 140 16 +46698 26050 12 +27409 22159 1 +7898 8636 7 +4270 50622 6 +1502 59231 2 +32890 12317 9 +37363 22990 10 +10396 34212 12 +48435 29766 9 +59570 48605 12 +11105 24496 9 +13224 141 13 +5305 20627 2 +53145 33881 6 +32117 38450 13 +34143 8164 6 +17790 35931 7 +36091 57403 10 +52692 45917 12 +11521 52689 10 +7147 30218 4 +21667 36113 12 +51060 30836 10 +9557 2286 11 +34288 16555 11 +31771 42875 2 +49344 8924 8 +44645 51670 17 +55269 53531 9 +23399 18920 4 +21213 26673 13 +33329 30371 14 +35071 19334 9 +8005 22103 12 +56513 35926 6 +12301 14993 17 +27475 13670 5 +34836 49199 5 +9453 14005 3 +15322 26892 4 +51360 18621 11 +2919 48037 8 +2091 19923 9 +50434 12106 1 +50999 58375 12 +58353 5561 6 +20075 26699 16 +15018 39160 10 +26758 55223 9 +21085 30463 12 +6713 46079 10 +16925 54965 11 +53119 35583 5 +55423 8765 7 +58890 14012 7 +12251 46319 8 +46273 22980 4 +16990 58752 15 +4847 5674 5 +52138 10924 9 +30214 15031 4 +20710 44189 8 +17831 34135 15 +40972 14033 12 +37291 35124 4 +49100 34800 10 +25191 907 5 +9088 37348 15 +19796 17017 7 +23854 34183 4 +57356 44208 0 +59763 10348 8 +50031 20019 11 +7669 1824 5 +12239 26685 0 +35560 32355 15 +24712 16007 11 +39665 28476 9 +15182 25950 4 +54674 16328 4 +53967 23040 4 +43731 54133 14 +52451 56066 8 +44164 58568 7 +54332 36441 10 +44658 27529 14 +48870 46311 11 +8460 44828 4 +9273 26869 11 +59096 40245 13 +14630 22890 14 +41025 11425 13 +32899 36884 2 +11838 46700 12 +8835 7032 10 +58944 47252 5 +52012 12801 14 +17404 26852 11 +24485 27934 8 +10691 23751 1 +44683 59886 11 +27005 57740 8 +375 1987 4 +47493 38065 11 +36213 17760 8 +44358 24613 15 +49684 9872 11 +32166 30965 8 +50546 25414 3 +16124 48200 2 +27342 8123 16 +28025 23788 8 +19858 19566 13 +22082 19897 8 +7625 27948 7 +22386 48641 2 +54103 20650 5 +16492 34664 5 +37126 46353 18 +22212 26260 6 +41609 48826 5 +20878 14347 11 +41057 2993 13 +43274 50910 11 +28450 19601 10 +31043 44897 0 +4554 24695 3 +15427 10429 3 +11355 644 15 +6185 27466 3 +13297 13386 9 +59689 7790 2 +13111 48516 11 +57452 5391 18 +55808 12027 10 +32515 595 16 +2297 44097 16 +55494 28111 10 +17637 12378 9 +27050 28151 0 +3583 1688 15 +22762 30738 17 +25905 14848 15 +28074 50886 10 +49110 40025 4 +49873 9609 3 +53620 53206 6 +10107 10688 2 +45404 42405 10 +3986 20113 14 +36969 50197 7 +385 11588 2 +14418 22776 7 +41590 12785 3 +16588 55598 13 +16084 8998 14 +41403 44379 13 +50898 9149 6 +33129 19419 9 +55259 20360 9 +57216 11488 15 +31025 7057 5 +12362 15151 10 +29820 12018 11 +22524 41909 3 +58838 1695 18 +1676 41807 1 +6897 18268 11 +32584 3861 13 +44866 32074 13 +11257 59793 10 +42255 54290 3 +30989 50368 8 +50288 51212 5 +20694 6147 14 +44367 26799 7 +34661 9133 8 +17815 15142 1 +54905 42673 10 +17456 9847 16 +52723 9420 5 +8611 57015 8 +58221 39483 7 +4109 42424 2 +30945 46753 14 +38861 57363 8 +49245 53746 2 +10078 4560 8 +30444 6098 9 +29244 17862 6 +17240 23266 10 +6419 49726 6 +35156 11376 12 +52884 13933 15 +45447 21577 8 +14155 36651 14 +10504 57281 13 +38681 49071 13 +56450 4498 4 +12352 5287 6 +4264 11577 4 +2255 48058 6 +59389 27161 13 +54237 32324 11 +27106 40978 17 +55164 28050 7 +29632 24193 16 +38787 45891 9 +57987 46313 13 +14442 48787 16 +12242 35829 9 +2200 27876 12 +40016 31555 10 +40142 37329 9 +48638 25517 2 +44691 18851 7 +8077 36315 4 +25423 26603 11 +10216 23536 4 +1339 31534 9 +44532 20367 14 +31653 27028 10 +19550 16625 4 +15871 41530 11 +24460 49661 16 +17097 19445 8 +15924 31003 13 +57517 27838 4 +17114 1485 12 +3745 30906 10 +45662 49474 4 +43627 3731 14 +40769 44725 2 +3542 54578 12 +7805 42895 13 +35516 29240 2 +11069 42591 7 +21879 49845 14 +48928 13287 6 +17254 30657 8 +20502 53979 10 +36699 58341 7 +31967 29708 12 +40069 10647 4 +5263 33502 13 +52076 51222 9 +37501 43028 11 +40836 33065 5 +10110 25589 10 +23524 9917 14 +29409 33957 7 +16783 8175 11 +56298 49351 2 +37882 30472 5 +29847 27933 10 +18354 932 15 +10 37640 7 +5738 17239 8 +20980 14044 13 +15886 26800 7 +56143 5136 13 +15012 22324 13 +33090 31046 8 +59424 35044 15 +659 51147 3 +41280 21384 15 +14004 14208 16 +22721 20831 5 +47258 16938 3 +22520 50249 7 +51116 43482 6 +18485 54530 6 +38820 523 11 +43422 13417 3 +50937 6524 9 +42324 57210 8 +53986 38315 7 +18382 6745 10 +57846 52312 6 +52203 28907 13 +35245 1503 15 +27962 29436 13 +11993 7199 8 +8988 3915 12 +23237 33673 5 +37858 46056 6 +21657 36 15 +7842 29128 5 +55441 5913 15 +8776 48754 13 +40610 49074 3 +21650 32773 9 +9485 13048 7 +52650 29146 8 +32708 47174 0 +25157 22831 3 +6043 9499 8 +17835 9401 9 +1641 14608 14 +13898 46913 10 +20877 49288 3 +51746 50107 11 +16864 29939 9 +53881 43107 9 +17074 51761 13 +8541 50338 4 +14696 2454 11 +914 20982 13 +32541 58817 8 +25416 36178 8 +16472 24071 11 +37915 35332 10 +15759 10554 2 +41020 26656 4 +7877 37328 5 +11471 88 4 +29052 2967 6 +19264 56551 7 +47173 9388 7 +31853 41656 8 +27227 20324 10 +28054 40406 15 +37203 40879 8 +11547 44677 5 +5520 22466 2 +56486 5479 10 +33488 48071 8 +3810 39580 10 +24816 45154 13 +31418 8218 6 +40876 40288 13 +7551 56238 13 +14781 58576 5 +25722 45604 9 +32683 20477 11 +50562 44377 11 +10674 33138 8 +24972 38350 9 +5502 55684 4 +47433 20499 8 +19332 39688 8 +46163 53676 11 +43637 16441 4 +22593 30442 14 +48017 53601 9 +37643 13138 5 +50708 38012 11 +4100 19437 17 +59709 49283 7 +16148 6765 10 +26968 25583 9 +48938 50047 16 +58981 19503 13 +20373 55610 9 +26457 57951 5 +22353 19426 8 +6101 10972 6 +20901 50913 11 +1317 18465 9 +51037 58089 5 +11156 12602 4 +59942 48639 16 +52421 25174 9 +38185 42553 10 +13737 18415 15 +52957 58467 14 +30739 52320 7 +43238 4865 8 +5192 46661 0 +42325 49140 11 +51572 57416 7 +22942 9277 6 +980 26229 14 +42643 6591 9 +42109 36694 11 +9153 46366 8 +45729 35540 10 +27714 43302 11 +30821 18873 14 +19656 53797 11 +36781 25337 8 +55375 46280 12 +50778 37047 5 +24735 18318 5 +45213 28536 7 +1801 48381 15 +45769 48408 5 +6377 25267 11 +28580 1602 5 +13397 57192 1 +23176 6146 1 +1803 13767 14 +2501 4254 16 +32027 750 11 +20120 30585 5 +24087 12363 11 +26254 7955 13 +18357 35016 9 +4060 18076 15 +4685 10090 3 +4287 478 15 +29952 20670 4 +3708 43308 9 +36984 52918 11 +20442 28613 5 +23587 45327 7 +5869 2239 15 +33599 41529 17 +18097 24983 11 +17465 21365 6 +16321 48651 15 +8429 9124 12 +54280 1741 14 +8217 31462 9 +26596 14999 10 +52586 7121 9 +42146 11961 9 +53557 38312 15 +11127 21702 5 +8458 50454 6 +57382 45559 5 +42308 47335 2 +51128 19285 11 +50157 44442 8 +50925 2638 14 +15215 5866 12 +23141 32498 11 +53418 36162 16 +31916 54395 3 +33187 40920 14 +39100 21558 8 +27421 33522 5 +56412 42980 8 +7918 43310 17 +56406 54721 11 +58493 33234 8 +18045 41593 8 +12211 38168 7 +20412 39485 9 +25979 21348 13 +52158 21425 6 +30388 38342 6 +57214 34947 4 +561 6211 5 +31133 54652 8 +17400 52039 5 +38082 47632 17 +30164 15506 6 +33039 59042 12 +15177 21239 12 +54727 41684 12 +40297 11827 17 +404 38654 12 +22920 11434 9 +53358 38277 6 +13464 5404 9 +21992 24009 13 +7367 8723 3 +11440 38905 10 +7054 3491 10 +8995 37352 13 +52946 11424 10 +31608 4663 11 +19082 5279 6 +33586 19934 10 +46848 14360 10 +19330 14327 7 +4051 15143 7 +9599 42213 5 +44123 45124 13 +12759 10752 15 +54811 29958 8 +37776 2197 9 +21491 10229 10 +8172 30951 2 +57312 23348 4 +58705 22341 4 +41257 17270 14 +7949 18035 10 +49921 22120 8 +1715 7934 2 +54055 1060 10 +42265 41623 8 +20271 32776 12 +11438 16684 8 +26029 55616 7 +14753 18486 1 +3057 33878 5 +38034 54608 7 +41580 51727 9 +9303 154 12 +1541 39779 12 +39206 50920 13 +25960 37631 6 +53765 3263 17 +34488 17985 12 +57556 42117 10 +25906 42142 8 +38290 32233 11 +6934 33161 12 +53699 680 11 +33449 6421 2 +14652 51953 10 +25087 40949 3 +5085 9202 10 +20066 1029 1 +22669 13029 0 +24554 25140 13 +44973 47523 13 +55713 33458 7 +48518 27892 9 +28851 34433 14 +15975 17998 11 +11938 13226 15 +58218 22231 7 +58738 47314 5 +50506 15920 7 +8345 31053 12 +45351 22529 8 +18275 42523 12 +44486 49553 16 +9555 12570 18 +44355 58769 6 +41279 54511 11 +38003 24805 11 +31527 22087 8 +9090 30163 6 +43719 58822 10 +30949 6980 8 +482 59127 18 +59209 42293 16 +10018 24846 4 +20962 15304 9 +16223 42932 9 +36907 8843 6 +6677 19917 9 +31127 38323 4 +31119 1514 13 +1556 49764 14 +33585 50118 12 +48066 56245 9 +44660 10233 8 +36611 42793 11 +29449 563 4 +21088 36962 5 +33236 14294 18 +30847 18897 6 +14804 10270 12 +1125 48177 8 +57219 52531 10 +12845 59175 1 +18167 30236 13 +55222 40516 2 +43764 55366 1 +26503 38738 10 +4275 59075 17 +8305 51082 15 +56705 11632 6 +43817 10337 10 +36201 38637 11 +55617 3901 1 +38085 34640 9 +54106 52686 12 +15986 39359 6 +40039 44126 1 +7431 40599 7 +15463 21790 13 +49005 1014 11 +44652 30901 9 +18060 5645 18 +13649 2764 10 +27834 13001 3 +10555 527 1 +30479 5750 13 +49530 4402 6 +8319 48608 5 +42093 35916 9 +21036 31086 11 +31764 42409 7 +42380 47220 7 +41696 12402 6 +8052 34775 3 +48805 25908 7 +55757 56923 15 +4422 3075 10 +32871 35733 9 +45231 12278 11 +15955 34778 1 +58488 22005 13 +23000 5766 13 +51441 16307 8 +48719 57052 9 +39877 49123 8 +50397 35849 5 +11323 41094 9 +31935 2911 11 +55263 4675 16 +25014 36550 13 +42994 47464 10 +40767 18221 14 +51384 51263 11 +51093 28754 18 +4461 51741 4 +33150 7035 16 +50004 53066 13 +52103 23839 10 +55851 51118 5 +2790 53235 10 +5532 41014 18 +11497 50816 15 +6764 41058 11 +34009 30505 15 +12136 42746 3 +24236 57359 7 +36018 19067 11 +3732 58404 10 +43534 18063 14 +30865 36385 9 +20227 1145 10 +43459 9293 8 +15158 15063 17 +52950 42560 13 +35533 56082 12 +7413 10660 11 +29893 32712 10 +2225 27697 1 +30290 28254 12 +38373 55158 6 +54146 14167 15 +2242 28850 12 +50935 53236 11 +48490 9123 13 +7483 28473 12 +5945 43489 11 +6037 20552 11 +23449 12165 12 +46335 40807 8 +7082 5147 2 +51791 29217 10 +6413 58729 4 +34817 19855 8 +3488 27894 1 +9099 59530 9 +44910 49980 12 +26379 8498 11 +45171 14692 6 +18362 41355 8 +15790 39234 10 +37067 47691 8 +51575 58950 9 +58618 36052 8 +56320 20520 6 +44099 8147 5 +27749 2844 7 +44537 39300 10 +4341 33688 4 +16631 42136 8 +48206 29210 15 +23002 6913 8 +44698 25372 10 +34523 34508 0 +25403 52825 9 +9816 55191 10 +20760 56035 7 +40044 12258 8 +38021 41254 13 +11174 8870 12 +24056 54873 5 +24721 37570 3 +29157 21018 8 +1311 10501 14 +12800 54802 11 +32660 42135 3 +24279 54090 3 +25873 47709 9 +41180 48514 12 +34017 30036 7 +14241 58283 12 +27904 34348 13 +23468 43000 11 +35080 9608 17 +34515 16207 7 +35494 48160 10 +56507 33415 13 +26300 35972 0 +22213 4869 7 +59277 37408 8 +49632 9316 11 +28867 58226 12 +5047 32297 6 +15788 23711 13 +42450 25924 9 +19999 15327 9 +3968 8361 15 +52829 52897 8 +27586 19686 4 +56430 2045 9 +9503 57742 15 +58097 43328 8 +36830 5253 16 +8038 41269 8 +1589 56325 9 +32083 51966 5 +53973 7043 8 +14607 15701 12 +52043 24000 13 +11216 52859 9 +51559 12683 13 +34767 3301 11 +39960 21196 1 +55007 10003 18 +34072 39743 13 +4493 28924 9 +41836 49135 4 +6041 13626 16 +3174 52981 8 +13301 16865 12 +50043 55 11 +59782 49379 13 +53718 9387 10 +32980 2226 13 +25614 22758 12 +9944 10007 9 +55151 17261 10 +54589 33162 13 +21102 53532 12 +23948 33230 8 +39565 30101 3 +30855 46453 11 +6131 58709 14 +29970 8202 8 +57981 54777 6 +33929 5667 7 +2914 14253 8 +8023 13071 9 +27513 34637 17 +37724 12392 9 +37143 59442 8 +10478 43784 10 +7888 18246 9 +55054 23328 11 +38404 43983 4 +54678 34828 10 +52598 18631 8 +48685 18115 5 +36043 11305 14 +41276 19298 8 +35217 51017 0 +39575 7330 9 +26896 21283 7 +47266 25024 7 +24166 59465 9 +34327 24562 11 +37193 57613 8 +38364 856 3 +518 753 14 +26388 20419 9 +11352 39449 8 +59126 57823 10 +24471 18587 7 +15807 7406 9 +35213 39685 6 +28955 15412 6 +32326 1530 1 +48334 27553 5 +54270 38544 11 +32699 41496 12 +20326 57892 7 +45641 23515 10 +5417 28470 13 +49776 40308 9 +26750 4726 14 +56843 35938 12 +38411 51367 5 +731 16185 12 +28237 20975 12 +25017 25669 7 +7311 20015 13 +18562 7134 12 +29983 7354 12 +52017 57572 16 +18770 38484 3 +36824 8447 3 +36037 56766 1 +5716 24143 8 +3662 28939 14 +13960 3373 9 +31717 43123 8 +18251 14280 16 +18896 3505 7 +34803 3295 1 +54493 50686 12 +55446 58532 7 +57411 6337 8 +46669 3450 10 +59371 20808 15 +29336 19867 5 +2093 46356 13 +24308 9380 3 +59619 30543 9 +57712 58333 7 +948 44275 11 +50892 53633 7 +24525 32653 3 +39027 4470 6 +10239 28125 1 +56077 56163 7 +15573 1536 8 +54927 52079 0 +30152 43292 8 +52088 37735 9 +52999 4951 5 +5144 43765 9 +19176 38519 10 +32330 49975 5 +25485 6310 10 +7762 11655 5 +11899 9535 9 +44018 48797 6 +53432 18943 2 +7817 44519 7 +8346 25565 13 +25253 24918 2 +5947 34554 13 +30363 56817 3 +3635 40523 9 +32743 23206 4 +48910 9536 11 +48942 94 12 +11054 40906 14 +5966 28076 1 +18804 34843 7 +56429 27234 9 +19366 24134 13 +12004 59366 3 +29781 39250 11 +20748 32686 7 +38025 53387 0 +35119 56185 11 +4721 12888 4 +14870 8643 4 +33523 27246 4 +45314 41702 9 +49775 42703 2 +31856 34427 9 +42262 2946 5 +22557 47891 14 +9517 15305 13 +8883 48881 4 +51033 17750 2 +13471 13947 5 +51259 34335 9 +59322 17685 4 +38128 1733 9 +21839 6982 7 +35100 26615 10 +34322 56413 17 +52264 48929 5 +18450 5517 14 +7476 31528 10 +8831 50879 6 +45109 807 10 +54412 22571 9 +31061 11110 3 +51328 22068 10 +2630 56956 9 +52235 45265 13 +58401 36709 12 +50507 16923 6 +21069 3076 9 +15183 39379 12 +30871 46822 0 +52574 40049 4 +29946 2009 4 +59498 5247 3 +15981 51779 5 +45039 51357 11 +31131 24221 16 +5552 48396 4 +20217 26936 16 +49376 42915 3 +12877 49095 11 +57972 12941 11 +23102 18240 12 +17521 45381 12 +44703 27902 9 +60 42480 9 +3918 7804 12 +2685 24741 17 +6327 16662 4 +44818 30653 7 +1486 37511 3 +15371 27819 13 +59418 36846 2 +27233 14886 11 +8604 30748 7 +53244 29534 10 +36932 49616 11 +22909 46779 13 +56838 3021 5 +31027 50413 17 +33549 7444 11 +35852 16986 11 +22074 41789 6 +9903 39476 3 +12311 47719 10 +58048 54066 10 +56229 12100 8 +16525 24389 1 +25900 27648 14 +56373 2282 11 +19556 33433 3 +54853 27737 1 +59310 38288 8 +7687 44865 7 +59121 50327 14 +2473 52728 0 +41646 10910 6 +53750 9988 8 +25226 51737 6 +55045 20685 3 +4258 40998 16 +48848 54165 2 +56971 52306 9 +13520 51793 9 +39305 29596 15 +59235 57810 8 +54310 50388 5 +24436 34948 5 +22563 14032 11 +46347 39086 7 +31058 6070 2 +39640 39911 18 +35204 41837 6 +28633 14714 8 +37037 44795 13 +54099 3233 10 +14457 51956 17 +12483 27435 6 +49496 14339 14 +27983 53289 13 +26607 58302 13 +259 2847 7 +15662 42500 9 +38385 45334 9 +4734 10247 16 +20872 44483 9 +9342 26911 4 +46421 29502 15 +12323 39597 3 +1525 4824 16 +39117 54823 10 +30141 18139 2 +56496 22794 5 +59381 52364 14 +485 12811 9 +31035 30991 13 +28634 24569 13 +10269 42168 6 +49257 17237 15 +50268 27285 14 +26204 21711 13 +33481 47234 9 +58354 57737 14 +30220 9543 8 +13872 20293 4 +10087 28343 5 +3206 20648 15 +6252 12039 7 +19651 56340 3 +30502 17902 16 +21373 34102 10 +56487 13466 14 +10899 37627 7 +37702 45152 9 +57792 42721 16 +34400 33104 12 +44669 46256 8 +2951 411 15 +49580 33966 5 +47 43680 10 +42870 50521 11 +43071 41998 8 +36561 37670 7 +28397 16226 13 +39390 38478 13 +21089 52311 17 +24599 57768 12 +33328 40310 7 +3728 14258 7 +25695 57594 6 +59785 15400 10 +22729 34506 12 +57183 9067 2 +31672 36232 12 +534 56966 9 +34682 56059 8 +36841 45820 7 +14156 19282 5 +13394 43224 8 +37845 56339 11 +58552 43304 14 +8863 52616 1 +15568 54379 8 +56481 22561 12 +893 5290 8 +14170 2519 14 +13971 13313 11 +16880 34862 11 +16117 22586 10 +845 10117 7 +6681 38833 6 +8285 29821 17 +45254 13368 6 +48178 38696 2 +39172 16965 17 +59984 15225 9 +11232 27209 3 +45113 49860 7 +6945 45866 11 +58392 55632 14 +3848 54467 11 +35090 45740 6 +21276 7187 7 +13396 26822 17 +2291 12644 10 +24414 7435 4 +46746 30359 7 +31442 40377 6 +4541 19148 10 +31463 9660 7 +47538 24511 12 +6831 27482 13 +57150 27053 12 +22266 2448 9 +54880 56978 13 +41984 59502 7 +49405 49356 13 +46001 36281 9 +47454 13094 11 +15128 49952 9 +55661 25346 8 +35788 51011 15 +52688 25028 9 +54201 51852 8 +30294 26407 12 +15243 43158 16 +29704 24789 3 +43832 39869 13 +21961 55770 12 +2654 42871 1 +49484 23297 6 +44366 34681 2 +45863 19409 13 +20112 1538 15 +54815 29548 8 +10949 11982 3 +34769 998 12 +30400 16330 12 +29154 39607 13 +53037 6649 5 +18192 17576 6 +34420 12525 13 +39541 108 1 +49587 5200 12 +5080 11805 10 +5380 36788 2 +32788 30158 6 +30572 10928 9 +25935 5978 5 +57016 45938 11 +36738 55019 7 +39136 37847 6 +11129 52508 0 +50361 14410 6 +18782 39108 8 +32967 9272 12 +24606 44376 10 +59344 33650 13 +21351 55887 16 +14112 400 4 +27966 17466 9 +7796 47411 5 +40587 46738 13 +34693 40564 15 +29818 36129 10 +58112 40085 15 +52993 18544 2 +7186 23114 6 +48458 45631 3 +13794 35237 15 +31047 9777 4 +15365 46580 11 +22554 51875 7 +17814 32219 12 +21659 38671 12 +17331 56288 4 +52891 6851 4 +21 52605 9 +1552 14596 11 +38753 47365 6 +26103 20347 3 +8813 47606 4 +18880 38729 1 +1729 23125 6 +15764 22594 5 +1544 54450 9 +10680 25881 11 +52167 27112 10 +57529 37697 6 +38731 13813 7 +22525 9845 9 +39438 19036 9 +6861 48372 10 +29928 31373 8 +54748 19657 8 +1817 9870 14 +11173 58076 15 +1847 24343 5 +40509 43840 8 +3992 27624 13 +35438 15915 13 +52731 19560 10 +5487 59038 3 +58809 20274 1 +7481 41525 6 +1770 45985 15 +35271 38159 4 +43403 24434 15 +35997 22219 11 +32047 32328 13 +20999 38950 13 +20898 20457 10 +10237 52983 8 +34211 14638 17 +4032 17081 18 +45944 47946 12 +54594 18710 16 +13315 24630 6 +11303 56603 5 +10015 48107 7 +51201 10912 7 +850 14097 4 +55184 22497 12 +2034 24023 10 +26108 3087 16 +27552 19977 7 +49262 38374 16 +56797 46394 6 +867 50958 3 +3852 42023 16 +303 26253 6 +40112 34142 11 +1663 29601 12 +20915 34597 12 +25063 31892 15 +45382 7987 10 +18858 25553 3 +3205 49502 13 +33583 20355 6 +19908 6667 3 +3625 46797 4 +59893 59116 5 +50897 9418 5 +39945 29856 14 +7818 14374 8 +10378 59520 8 +22009 10334 6 +52011 13718 9 +34454 56064 14 +12418 55642 13 +7566 42485 1 +42877 32339 3 +52251 57018 11 +14186 17190 15 +20633 5654 10 +50115 26611 15 +51253 1953 16 +37757 56653 16 +51165 36640 13 +53785 16086 1 +6348 15583 2 +10778 39215 7 +29131 31129 9 +37972 21913 9 +10998 38718 4 +40894 47422 6 +38028 38743 13 +6010 36313 16 +18274 38712 6 +33195 43326 6 +54648 20767 12 +44316 45943 4 +20488 24227 3 +24632 13462 11 +20958 54885 6 +47471 40109 8 +48346 50874 13 +53744 3409 2 +51910 51751 11 +55922 1802 6 +4732 33426 10 +47897 24728 11 +26164 3790 9 +33036 36548 12 +51322 7856 15 +27147 47101 10 +50018 53287 3 +19510 53315 9 +16062 19548 4 +20458 9335 6 +20656 9575 8 +38090 11617 14 +43284 1545 11 +49152 18888 9 +25572 45889 8 +364 52657 10 +56952 5288 8 +58021 3873 9 +20029 22276 6 +36070 36706 10 +55427 32057 6 +36486 38445 12 +47020 59059 5 +40581 23606 2 +55329 22741 10 +19496 55445 14 +19573 52471 11 +28390 6397 15 +54817 7214 3 +58259 3813 8 +29532 2769 3 +19253 36557 12 +4988 41737 8 +30531 49022 13 +15799 31484 6 +43193 53272 14 +45475 4738 0 +46354 41544 11 +22840 27620 6 +29913 18336 9 +46071 29205 9 +13407 59079 17 +23997 12787 12 +37178 29316 13 +54143 17134 1 +49116 11400 14 +37064 21318 14 +6609 33098 10 +33413 36981 7 +23490 1381 10 +27477 12233 7 +34261 40017 8 +23691 49201 10 +5854 42369 4 +54241 32796 13 +31281 15321 10 +53974 52490 11 +27960 6565 4 +55949 43629 17 +18709 11379 9 +24206 40132 3 +23589 4222 9 +41417 32221 2 +57146 52056 5 +19010 55838 6 +48105 52601 10 +5243 42894 9 +23992 1966 12 +1184 35239 15 +44105 44657 6 +39632 30725 10 +49325 203 7 +21752 17591 15 +51298 26868 10 +31963 32641 9 +14408 47344 1 +31600 34057 8 +26006 55016 8 +25903 55842 11 +53367 43816 5 +11251 18313 7 +18591 48561 10 +15760 18845 5 +41776 53905 7 +7457 53456 14 +29269 42209 12 +46268 32730 4 +25012 53130 12 +59312 3251 12 +29215 2106 5 +56462 12053 9 +31606 46502 14 +30783 37188 12 +42289 51507 15 +46981 23262 12 +30740 39035 11 +20192 16664 5 +17863 40591 12 +18694 34468 13 +51935 42104 15 +10401 10343 5 +3815 46166 3 +35679 23484 6 +32090 41934 10 +9685 10435 9 +55025 16593 8 +54626 23623 12 +53598 58884 7 +46859 45890 11 +43275 18634 6 +34887 22377 7 +33758 30528 8 +40447 4703 7 +36188 27326 7 +16286 39183 7 +47574 8337 11 +56894 16417 16 +32012 15622 12 +33250 34841 7 +32308 40093 10 +41350 8432 8 +47298 14850 15 +6057 53709 5 +24935 888 14 +50184 41660 10 +58927 37478 12 +36832 43934 13 +33017 8029 15 +31179 20193 10 +54750 59315 8 +58954 29045 5 +19653 45528 11 +1699 49033 9 +19123 36402 13 +52782 11134 3 +49625 51694 6 +12755 25664 13 +23379 5751 8 +20945 11847 17 +47338 802 7 +26796 52202 6 +56047 42706 11 +42697 33659 6 +20789 38064 16 +44216 32705 4 +32877 2896 11 +28822 59537 3 +1248 56777 4 +50813 5482 4 +49366 2103 9 +28744 33237 2 +10953 27023 3 +57674 1115 10 +9109 1289 12 +45300 35054 15 +42022 10274 14 +35609 29838 11 +35539 32621 7 +11852 13215 4 +37993 43596 15 +21630 44671 5 +17179 18698 17 +28416 3015 9 +4900 14606 2 +44678 45200 16 +2906 11536 10 +17977 50203 4 +43526 43835 13 +16901 44037 12 +24917 1262 9 +45898 32429 17 +23719 58181 10 +54820 4022 9 +16732 49574 12 +9257 28858 3 +36872 20473 5 +44717 3003 15 +7531 38242 12 +23512 44520 11 +8486 49778 3 +8898 3834 15 +1464 6262 9 +58476 15762 5 +40158 49303 16 +42446 56159 0 +55314 35126 10 +40950 13436 12 +32832 12604 9 +37625 13691 10 +9938 25717 11 +4356 4506 3 +16509 43604 5 +18947 35618 10 +49649 58643 13 +55706 4586 14 +34646 3941 6 +36780 5281 8 +13062 59078 8 +43294 27465 3 +38043 12473 8 +17607 46261 10 +44588 8904 8 +29341 32536 1 +45243 51799 7 +48875 25521 13 +41460 56351 2 +49234 33383 4 +24010 59904 5 +24310 21223 9 +28124 37088 13 +36524 3855 3 +56892 15676 12 +23366 7384 16 +34287 3979 10 +22974 57919 7 +35029 15313 9 +22418 41764 12 +38122 56020 5 +22160 45135 9 +57333 45260 12 +35067 48065 3 +32043 42856 12 +22284 35082 7 +37084 28803 5 +27079 53097 12 +39226 26480 10 +43609 53596 12 +54298 25527 14 +11989 40088 13 +41164 47323 16 +16022 26104 9 +12762 8352 12 +26524 52299 10 +50936 17531 12 +54042 13544 4 +55156 41240 15 +38730 2100 6 +19226 57255 14 +15197 22792 7 +57028 12308 13 +27839 54181 18 +36218 18078 12 +48498 58679 11 +56750 39307 9 +31616 3862 6 +35055 32614 11 +17301 51533 3 +54882 44202 15 +29971 6634 15 +19403 56032 14 +50519 40541 15 +29176 15537 4 +16603 23878 9 +55396 34278 12 +7725 7425 12 +44 28890 9 +47584 53065 14 +21257 21569 14 +43850 40156 6 +58955 26679 10 +24584 19935 3 +28080 36244 10 +55113 30407 15 +17881 59652 3 +47754 32972 11 +16466 30481 11 +29000 49232 3 +19695 50066 10 +33708 32242 10 +49573 32240 8 +9885 28419 15 +29061 48687 8 +19236 27167 8 +51016 26291 5 +23106 36783 2 +50705 29686 8 +18119 8055 6 +7677 602 12 +3212 314 5 +20614 28064 15 +32079 51470 10 +24492 59211 14 +8459 55271 6 +14986 28256 4 +5351 33006 7 +48529 51487 8 +39787 35027 15 +19173 9017 6 +50306 943 8 +25314 15908 13 +16807 45555 13 +50244 14503 8 +1183 7608 9 +58683 19785 16 +32243 32734 8 +46413 10086 16 +51468 1209 1 +30797 47528 10 +18688 24868 12 +6264 36674 9 +45150 38073 8 +24311 48417 10 +51734 32457 15 +1758 32864 16 +40143 15549 12 +23888 11247 10 +28312 20802 5 +25242 3404 10 +3471 30249 9 +8763 57745 8 +4167 22455 6 +40171 47041 1 +45356 26065 14 +34492 16569 9 +59284 50279 11 +34118 7580 13 +36435 26832 4 +21421 29411 14 +49319 19981 17 +30623 30421 15 +37661 9107 4 +35549 38213 14 +29644 44062 13 +54213 5005 9 +40067 47432 13 +3671 29241 10 +58287 1915 3 +21377 51389 16 +46123 14641 15 +47389 51841 8 +10902 54257 12 +26518 28990 16 +34038 28556 5 +7656 28840 1 +31236 36501 9 +46014 16165 5 +38176 43085 7 +42050 47624 7 +26416 49010 18 +23337 42399 7 +34259 17294 8 +39524 18075 8 +9025 20641 13 +35280 41753 9 +43936 32092 5 +53343 17027 10 +25507 13044 2 +38683 25449 8 +59086 17982 14 +4093 39373 17 +18499 19317 10 +31864 48931 2 +25547 55347 9 +45276 46167 6 +46684 50756 8 +35737 43722 8 +46230 57137 11 +54964 2325 7 +47746 18463 6 +19739 703 10 +42334 30468 8 +45445 206 9 +7680 33571 16 +58550 40327 4 +25301 26975 11 +12007 31760 15 +4791 56120 6 +55349 56156 14 +32350 33785 11 +43743 21068 3 +58518 25663 10 +40082 15373 4 +3718 54663 14 +46713 1964 13 +37772 56219 9 +4597 53229 5 +10587 43267 5 +43264 14289 15 +57117 50655 7 +10855 21099 9 +59836 7525 8 +15484 57528 11 +20046 8752 3 +48864 40202 9 +9435 42363 7 +56811 31083 10 +34162 5321 1 +34930 55165 17 +19306 39235 8 +25995 36716 7 +5424 34954 14 +34875 15097 7 +26409 48063 3 +29312 8181 10 +40896 47513 1 +53002 434 17 +59541 46275 1 +54126 39861 3 +31716 8324 8 +14454 38658 8 +47951 31686 11 +38867 41431 11 +6245 57624 2 +13780 22389 14 +16888 53897 0 +53610 7282 5 +58704 35084 11 +17950 39009 15 +38031 28514 16 +3385 17608 10 +33120 24791 10 +19931 45033 12 +36580 11864 12 +32418 34532 4 +20097 2250 10 +9884 22237 7 +6520 51682 11 +46293 49918 9 +54148 9704 11 +18630 7208 12 +2129 5012 5 +36337 1815 4 +54243 44558 8 +44167 33096 6 +3628 33505 3 +34755 17994 14 +17090 52117 10 +38525 5150 5 +20851 31164 8 +37139 44767 3 +37341 35089 6 +4150 43047 8 +52444 28548 7 +498 27048 14 +50834 38487 4 +22098 58733 11 +34537 18769 9 +50467 36045 10 +13244 50211 9 +53646 21126 12 +58599 36474 9 +42457 51712 13 +30664 35278 8 +21661 6642 7 +27198 12920 9 +31231 7819 7 +55331 13264 13 +52433 48654 11 +2206 25052 5 +20792 58169 18 +38135 49391 15 +24515 40929 9 +11132 31755 7 +51010 35627 7 +20637 14027 10 +47971 30269 6 +918 36827 16 +24577 27292 13 +12479 29916 6 +41285 2468 3 +46846 7959 11 +39669 29895 2 +7387 34752 7 +31809 25791 13 +11696 30979 12 +35554 58716 9 +21492 45017 5 +16772 54443 11 +2513 32822 7 +28565 54508 9 +14521 22338 10 +57506 32895 6 +40153 44975 8 +42069 26536 18 +25540 29676 1 +960 21307 9 +38351 48431 11 +34819 44104 17 +41504 37790 8 +21333 14864 10 +11553 59944 7 +56391 23202 6 +12333 39888 4 +4499 34938 8 +43546 39974 11 +10207 26460 7 +16955 41338 8 +2629 10725 6 +29177 23452 5 +962 19581 7 +28902 2138 14 +44525 4497 8 +47368 22660 8 +3199 15914 8 +27746 32157 4 +35185 53549 7 +33748 53031 9 +38993 57714 1 +2582 47085 8 +1441 26181 15 +10346 6769 10 +5977 12843 13 +15717 16744 5 +56660 22711 8 +18434 19493 15 +26340 6368 11 +9141 20741 7 +37814 50842 1 +27920 14303 4 +31637 7694 12 +37650 31480 10 +48295 27335 4 +39998 28386 15 +47698 18102 7 +22445 17053 7 +49446 45083 3 +2943 42225 10 +23227 2193 8 +27693 4648 3 +41967 35275 1 +6660 27581 14 +39170 52212 8 +41387 31969 5 +48166 38621 14 +57419 7939 8 +27041 49193 7 +39912 8781 2 +39339 12672 6 +48502 53704 5 +20902 15625 9 +30480 20747 0 +23574 42896 9 +23034 44878 10 +7676 6028 13 +329 55832 5 +19151 16311 9 +45790 25037 7 +11244 5028 8 +28946 150 4 +48061 23353 2 +3329 44404 7 +11506 24101 16 +4434 25931 12 +34075 5724 10 +25506 33882 11 +4594 52511 17 +11736 43679 13 +46774 47974 14 +45422 55352 2 +4072 17223 6 +50228 59060 10 +32957 42238 15 +14051 42726 8 +47123 30817 8 +11625 55472 11 +999 44050 13 +2303 11445 9 +21503 427 4 +25348 37400 16 +32183 14515 8 +50675 5864 6 +28360 27932 14 +30787 10219 9 +43859 29677 7 +57352 28610 12 +15786 23190 9 +27153 17525 7 +55243 50419 13 +40561 6983 6 +47786 20216 9 +13413 37586 10 +14715 27236 12 +36777 38809 18 +37137 45 14 +7105 9697 2 +33193 47845 13 +27507 59068 14 +51845 5225 1 +45125 41070 11 +51333 37827 6 +57657 14952 15 +14767 55473 10 +13769 46379 3 +28935 11880 16 +12968 4186 4 +47704 1237 8 +42501 15275 7 +35933 19979 5 +51029 14785 4 +30233 29022 13 +20462 55751 12 +26552 44799 8 +21204 43990 12 +56138 9151 1 +13459 19328 5 +54496 8914 10 +4463 26695 11 +12047 27941 11 +30508 36577 5 +59182 40638 14 +30129 33675 2 +28533 3988 7 +53966 44263 6 +8894 9971 0 +8588 93 7 +25215 48531 11 +11295 47364 7 +25810 56453 16 +31364 50588 15 +40274 49421 10 +16389 41865 8 +25875 286 10 +57584 3712 5 +10721 45096 11 +45709 21233 9 +4787 58438 10 +47073 42234 6 +21330 56013 7 +23339 56673 10 +40148 47086 5 +23876 10914 9 +24620 30529 13 +54612 7575 16 +23423 22432 9 +9274 24557 9 +46808 24155 12 +38379 39560 7 +18080 24657 13 +769 15040 10 +47949 22773 13 +15884 3642 7 +52819 54319 5 +10046 32524 11 +20123 38673 9 +23631 45578 12 +13439 48785 13 +10879 43907 14 +38205 7404 10 +36708 58792 17 +16871 53416 13 +28490 36532 9 +15932 24776 7 +19157 38046 15 +1296 38716 12 +55293 8701 16 +30010 38841 17 +23062 58652 15 +175 28412 5 +28341 31289 14 +41071 13249 5 +33574 57156 9 +55439 42116 11 +13447 4378 17 +31275 21111 16 +6706 20387 11 +30596 47451 8 +54451 29848 9 +19745 21498 7 +1971 23488 6 +46487 41828 10 +6777 29012 16 +27199 22339 13 +27081 36680 8 +35976 52046 6 +43232 46756 9 +48242 25707 7 +19411 5328 4 +52603 17877 7 +5059 161 9 +6603 1948 8 +21583 17635 7 +5555 3976 15 +35817 17564 14 +33566 39757 4 +25342 46616 13 +58197 31234 7 +51171 34853 5 +2821 24938 16 +54247 24564 3 +8507 4880 10 +38987 53011 16 +55034 53945 11 +33123 24906 10 +14123 22170 2 +53427 19441 2 +33916 41709 14 +42692 322 11 +20109 38929 5 +4485 29070 8 +34643 24371 2 +37747 58551 8 +50527 35045 5 +24690 59973 11 +49276 31340 12 +21902 4466 14 +40796 10443 10 +52291 10739 3 +17257 38524 7 +18649 24647 2 +24046 40750 16 +16356 45361 12 +27900 20846 0 +25892 25159 0 +19185 3230 10 +35149 48936 5 +58209 53838 7 +17253 27559 9 +12580 55111 14 +14523 13903 3 +58745 49908 3 +55585 48681 6 +27539 8583 9 +55935 46900 5 +26967 9150 16 +11431 55205 15 +24731 53423 10 +45964 1182 8 +55941 45155 8 +27166 30135 16 +50666 36030 7 +59032 21436 8 +34590 20568 3 +9252 48647 11 +15524 46363 7 +58699 28163 15 +49131 25223 6 +51273 21053 4 +29 1842 11 +28083 42411 10 +7394 7164 2 +41829 22859 7 +25963 14617 8 +12518 54338 8 +36928 44983 5 +38059 40957 13 +51929 38740 13 +53488 57820 6 +5413 4409 10 +10703 56830 11 +19077 13329 12 +34207 18291 15 +49807 23360 8 +3183 42337 9 +29296 4609 15 +6895 5717 9 +45705 53887 3 +19373 41087 4 +39398 57113 4 +3387 4476 8 +49987 56508 2 +26338 3254 8 +34111 4695 12 +1453 6608 12 +41120 42042 8 +43588 2907 9 +2953 24650 14 +24483 15095 2 +46002 28276 5 +15065 42 7 +44398 57026 11 +16208 56225 6 +23036 32620 8 +11111 50953 5 +25111 53587 6 +33403 40613 0 +10729 44535 10 +53443 22097 12 +51209 48724 16 +55071 39953 12 +45204 59406 6 +48091 31713 10 +34826 45103 9 +1598 10323 8 +32989 19499 6 +36796 24462 9 +52137 47823 11 +27824 58478 8 +32516 11481 11 +58490 9247 16 +21898 19382 6 +2237 53370 17 +44914 26635 9 +10570 38838 9 +20117 40683 3 +43963 24925 8 +24543 42862 4 +23800 11996 8 +53203 32275 11 +14902 4937 11 +6254 17802 2 +35436 59246 8 +39439 54604 12 +32003 57954 12 +45496 25381 9 +34854 16848 7 +41267 24180 8 +29345 45991 5 +4358 1320 10 +56879 41869 14 +8886 58215 4 +34487 31493 9 +3293 44972 15 +38703 9233 12 +37401 25273 11 +54123 36543 3 +18429 7993 8 +25687 51356 3 +57398 59798 5 +36961 18181 8 +1383 58549 15 +9979 30148 3 +7716 24441 7 +56149 37612 8 +34170 21968 7 +1313 44974 13 +26138 50323 14 +20096 29376 10 +45297 13345 6 +57284 31915 10 +22400 51974 11 +40124 45041 8 +24085 1035 3 +5039 57730 6 +17529 57516 10 +46972 52239 18 +19828 32268 6 +22405 8503 9 +13362 41650 16 +53775 54667 15 +32924 54745 11 +40756 23071 13 +57802 32175 14 +12690 4556 0 +17666 21306 12 +35222 51350 10 +35923 2162 1 +56203 43736 11 +54373 11994 8 +49197 43986 8 +629 23594 9 +30262 10051 10 +22472 50256 4 +14368 56606 5 +54017 57623 13 +21150 40407 9 +42816 13662 11 +41804 5857 9 +1747 23775 8 +520 33689 15 +37420 7417 11 +10036 27064 7 +40449 34200 11 +36461 34684 4 +8517 16562 8 +36246 50138 9 +41643 4004 5 +8629 11612 7 +4354 25277 16 +37975 32760 12 +34410 56913 15 +51847 54524 4 +45331 27936 1 +16877 25773 9 +9636 50469 9 +9943 32672 15 +21248 6864 2 +6527 16423 5 +45346 41811 2 +7307 5418 16 +26127 54174 6 +38804 26694 6 +46339 44815 0 +46534 19414 7 +15876 20746 5 +58083 10208 10 +42967 30485 3 +15564 35264 8 +35504 872 3 +51289 3744 17 +41691 13954 12 +43086 34448 14 +52627 55799 8 +59232 9073 9 +23557 41040 9 +54214 40883 3 +25926 16277 15 +35474 37550 14 +52759 53892 12 +38803 16913 8 +10961 22846 10 +45809 5048 3 +6695 14565 13 +31266 38245 8 +4984 52809 7 +16398 18661 10 +50290 55982 4 +36715 36339 6 +3097 47649 8 +19361 45115 0 +20842 22505 12 +12071 15934 1 +17779 3627 2 +19814 11178 10 +30142 3083 15 +51544 55525 3 +20828 39141 9 +2754 27077 11 +40670 45913 17 +39228 43013 2 +57076 59941 8 +10475 56595 10 +44474 46959 8 +56314 34370 10 +55944 14672 9 +58574 53349 16 +43532 39279 8 +27352 48298 11 +35704 47882 16 +51448 8264 5 +41357 21858 4 +57019 41482 12 +26439 50040 14 +1455 12579 16 +12228 26391 6 +25013 15080 10 +40097 53828 7 +9580 55880 14 +45586 4015 8 +19057 15610 15 +51285 5097 4 +28698 21156 9 +41416 57482 12 +26316 8915 17 +47542 34686 7 +54739 4010 4 +25946 59020 13 +40432 43337 12 +46826 3262 0 +9412 46989 8 +27337 31350 5 +39828 53039 4 +43260 40154 11 +55290 59004 2 +5952 56899 8 +30070 52505 4 +14642 55631 7 +32483 52905 17 +8120 10712 4 +21529 9997 14 +20353 19693 8 +45777 45126 7 +15550 53970 9 +21082 25537 1 +29905 8372 11 +0 19671 6 +24624 8331 2 +44631 23905 14 +22259 53353 7 +25274 34626 6 +34431 59147 14 +25183 46168 15 +16814 38925 15 +46612 46359 11 +27841 21481 5 +46575 2312 10 +19232 17483 9 +2774 46854 6 +46481 36937 1 +28929 59741 11 +6142 22301 8 +12694 53226 9 +187 33693 8 +1110 25728 7 +56842 13574 9 +40697 34341 17 +53430 17495 7 +12960 2221 17 +1716 20413 4 +1468 47770 6 +23562 56575 9 +44248 42972 8 +12474 28827 3 +10925 27773 15 +42421 5276 13 +9349 21230 9 +25917 29727 13 +24339 31981 7 +13031 9554 10 +50940 56622 12 +6653 51251 9 +45664 53504 8 +48733 59692 6 +2414 34237 5 +1084 15447 7 +14987 46182 11 +48451 48004 11 +31097 45589 9 +91 36646 7 +45580 55209 8 +32216 8940 8 +24691 4213 16 +37644 39675 11 +17187 34866 3 +19163 22740 16 +41116 55503 9 +54776 3335 11 +57606 1993 7 +13853 17776 7 +10490 26411 13 +58811 16727 11 +15495 47502 3 +29309 34201 9 +1259 5142 10 +45735 5478 16 +32045 59902 5 +30702 15599 12 +55620 36977 12 +53436 30580 3 +46259 1329 10 +10526 36058 11 +21535 57824 6 +26372 17864 9 +35577 26752 13 +3884 10012 8 +18736 20211 11 +16652 48576 9 +46598 33922 5 +46173 44668 5 +107 36389 12 +22898 47996 13 +27460 52324 18 +51100 19902 2 +42528 31604 7 +52743 14775 9 +47438 51940 11 +57451 1542 8 +5579 5902 9 +28327 26557 12 +50515 2428 14 +50991 44343 10 +49150 968 7 +45519 57706 9 +56527 47156 9 +26433 55958 8 +32279 28829 14 +41761 8392 14 +3831 2462 2 +50096 47013 10 +36347 8672 11 +4309 42491 7 +12423 10326 6 +52205 46078 8 +44304 5101 6 +33101 4693 17 +33420 190 7 +34089 59594 12 +57092 50420 5 +20156 11462 6 +54503 41644 15 +14447 29817 8 +42659 40693 6 +1494 31165 6 +53652 58805 10 +58849 26124 14 +47453 39894 11 +38130 19834 6 +36579 50699 9 +52065 24137 13 +17174 31030 14 +51850 58500 8 +48172 59518 13 +38727 4842 16 +3574 9861 10 +45879 34732 16 +1933 24340 11 +46321 4744 7 +16567 42440 3 +16215 35247 10 +57944 42197 6 +54692 5248 9 +29318 54546 18 +32978 12838 9 +23105 29350 11 +5898 48478 13 +1220 45105 5 +30131 159 5 +2624 383 9 +12743 35778 1 +35635 25011 11 +13977 8189 7 +5956 51526 13 +25026 47985 8 +2506 11389 7 +14758 49813 4 +9307 15263 9 +40935 12887 14 +14416 55391 8 +6407 7581 11 +13924 27623 15 +2427 41582 12 +52863 19650 16 +39165 13068 10 +43508 47792 11 +26131 28654 10 +50512 16534 14 +58527 24248 6 +48185 32930 9 +618 27570 4 +29577 23663 7 +31036 58303 10 +2605 58403 10 +5755 33907 13 +11870 52883 15 +42052 24742 16 +12406 34690 16 +53371 19475 9 +12322 58325 8 +33626 27247 4 +58976 36949 7 +47923 1402 5 +39940 2862 11 +10301 29850 8 +26946 52081 7 +12627 10733 16 +24409 56283 8 +47553 13351 7 +13281 54087 9 +40053 13939 8 +13623 46077 1 +6488 41673 6 +20431 33258 12 +28985 31739 3 +40939 26134 13 +23647 22459 4 +37123 5125 18 +35342 2935 6 +39622 41038 1 +4596 31248 13 +6732 49606 7 +10431 13393 15 +18958 51675 4 +19952 15283 8 +48778 46217 8 +54416 46620 3 +53544 49224 9 +9377 7007 3 +34303 9172 8 +52383 53688 12 +23367 10481 6 +951 48306 2 +4352 14764 9 +49702 39308 10 +3990 26113 9 +24837 30799 12 +47999 26343 2 +45420 13624 4 +9920 15690 11 +19627 20406 13 +43212 16268 10 +51175 37870 12 +11328 6879 11 +30679 50526 3 +42408 37934 17 +16948 55411 3 +55464 22176 18 +34782 20528 6 +25442 50240 2 +59874 17717 8 +47355 25637 18 +57042 48873 11 +836 231 6 +36668 8430 5 +7845 57466 9 +28953 50318 12 +37636 42809 7 +38957 17901 7 +36834 16740 17 +37547 6049 5 +55091 27772 4 +35962 37569 9 +39058 30763 8 +1846 35944 10 +30304 54031 12 +48756 25948 9 +29637 44264 9 +24836 19150 3 +15615 4056 13 +20371 2514 9 +19309 18178 6 +9305 6891 14 +42957 51345 11 +57406 50865 15 +57107 57313 9 +39950 47546 9 +25767 37732 2 +28229 21544 9 +19579 5629 9 +30401 40744 9 +54851 14407 15 +17305 21626 6 +46385 4403 4 +21737 50274 9 +9363 40603 10 +18348 31833 17 +43461 39000 16 +58494 11326 3 +8762 39487 5 +58317 5595 11 +12161 30328 11 +2662 31930 7 +30976 39237 3 +36537 54775 1 +50312 49148 5 +28811 20686 3 +29439 43366 6 +26363 41839 6 +59642 39118 8 +39744 19545 5 +49527 29225 8 +29783 28073 14 +53192 18776 6 +37473 29200 10 +3715 16920 8 +45091 27438 11 +52051 44774 8 +24781 23350 12 +51932 934 8 +33592 43261 10 +14697 18998 10 +16087 51747 9 +59670 19914 14 +25388 20191 16 +25536 21034 8 +32450 37490 6 +16775 24968 11 +35081 14914 9 +58591 44242 2 +21295 28979 9 +50955 25478 12 +14194 4781 8 +11597 31837 2 +58274 52655 9 +33805 48047 8 +14389 38826 7 +59734 20401 8 +33210 22442 4 +51868 34104 13 +51807 29920 16 +45523 30161 12 +12469 54788 12 +23942 46395 10 +32854 19971 11 +45336 30284 6 +42080 24732 8 +44872 34029 8 +23078 43746 9 +40947 58356 3 +19097 31780 3 +32184 53748 2 +51483 53630 4 +10846 9059 5 +7560 56137 4 +35376 38752 6 +24156 34744 13 +8563 58533 11 +47304 5412 11 +36056 7265 4 +25886 8650 9 +28901 32140 7 +16899 48871 5 +49636 18672 11 +14884 40778 9 +12764 35998 7 +47332 25022 9 +59609 21459 12 +58603 26724 7 +33535 58441 3 +15611 26450 9 +47369 5356 6 +5765 26512 18 +41840 50286 12 +16572 27865 4 +3864 58405 13 +36072 19331 8 +28040 14526 11 +30612 50389 5 +2851 8304 2 +24442 22895 12 +27793 6990 5 +5807 23664 8 +51172 33078 8 +40902 42320 12 +15951 9497 12 +47504 9356 14 +58632 14754 13 +21538 55781 14 +3809 51402 6 +49397 49926 4 +12111 27782 12 +24006 57418 10 +58707 28774 12 +16274 47308 12 +48946 3351 6 +1146 3219 11 +59174 32887 10 +41429 41688 8 +49590 53093 11 +44907 54946 6 +2251 14533 5 +46317 55183 4 +4016 59275 5 +56954 35023 2 +29119 16405 5 +41694 10975 1 +34791 35392 10 +53238 40072 15 +50769 52307 3 +5326 14826 15 +34738 20266 13 +34279 39797 5 +19852 18781 6 +37740 859 5 +19756 26399 11 +17759 39120 6 +976 4789 12 +16137 4800 15 +24347 21044 4 +46043 6392 12 +38125 9644 8 +58471 10017 11 +56969 1127 7 +50648 7514 15 +23760 14508 9 +25036 54893 3 +12499 29948 8 +42566 49575 9 +3772 42333 10 +2553 38112 17 +15941 29303 16 +31348 45525 10 +39995 22767 11 +46188 50632 6 +14119 18244 4 +7563 51623 1 +53401 46491 6 +23032 21268 6 +11770 45147 5 +49742 48538 13 +17091 21836 9 +46326 18361 3 +54324 35008 5 +8213 12897 8 +10929 33749 14 +47051 56162 14 +37399 29622 13 +98 49740 12 +43389 10293 2 +27354 44336 7 +47014 58570 7 +33780 28650 9 +35026 38749 6 +14906 37412 3 +3250 35206 13 +24064 24201 13 +44940 47788 16 +22073 24834 6 +45500 49378 5 +24738 12710 9 +25002 26528 12 +42532 2089 6 +21829 6227 1 +25872 20280 16 +41871 25297 13 +16667 16003 9 +53322 17082 5 +11884 33061 18 +3764 57134 13 +4087 16725 14 +48308 22007 14 +30486 51202 5 +52962 48203 13 +33401 4894 15 +10978 23941 9 +17946 19355 8 +32370 23571 13 +38286 25877 11 +18704 838 7 +9268 37919 12 +30347 52282 14 +21157 57087 13 +55425 4538 11 +11249 44890 10 +2562 41745 11 +29990 12145 3 +47942 55149 10 +46510 36114 10 +42605 44597 11 +31838 51403 9 +6017 49470 13 +10895 25827 10 +47351 45724 11 +9404 47672 2 +27806 15826 6 +3846 4360 13 +19466 26295 3 +59082 2232 10 +19511 19666 11 +38332 28315 5 +26140 3626 6 +1596 35546 4 +19417 20782 15 +56996 59106 13 +55028 4606 12 +51442 12823 11 +8980 15293 8 +44033 7882 2 +16604 8882 9 +20560 14878 11 +48175 56534 8 +56560 25841 15 +14737 29067 5 +53661 36983 17 +7300 48323 10 +6082 28747 5 +41782 17724 13 +27951 47582 8 +24287 414 8 +56433 22359 14 +14319 5711 0 +44346 19206 12 +41567 3494 8 +37684 33440 8 +28022 3856 10 +3071 30982 11 +51321 46605 10 +30820 50544 15 +601 55208 14 +24604 8601 13 +57376 26839 16 +52262 52335 3 +43124 32879 3 +42665 41676 14 +45826 8982 5 +45301 46231 17 +37603 40163 8 +45405 54093 10 +50450 18483 8 +37918 40869 7 +19165 35877 11 +13305 37969 7 +32061 14000 9 +7052 20658 0 +45721 32963 9 +35399 16469 7 +25814 30781 8 +4171 426 12 +34198 37049 11 +55256 2566 13 +12713 8282 11 +17259 23661 8 +27781 45003 7 +733 14056 1 +21027 29374 5 +36161 51573 9 +4603 32322 7 +42199 20931 9 +35585 13359 13 +431 8419 11 +12208 4304 12 +13032 47694 15 +25824 49686 14 +25611 58474 10 +58487 54490 8 +5984 14933 10 +4857 51210 6 +50985 52960 12 +2015 49848 1 +10377 26971 15 +34721 37395 7 +18607 53260 8 +34429 15954 11 +48971 23834 9 +4861 47868 2 +11836 47089 12 +14580 3794 15 +54351 12958 8 +37075 55311 16 +35961 24995 12 +35698 13087 7 +44881 41274 11 +55340 25811 8 +56109 58967 16 +13409 52846 18 +27818 45000 8 +49352 16697 7 +33015 47778 12 +27873 58687 16 +18122 44653 9 +52747 12949 4 +46403 28971 3 +13858 52214 15 +38857 51856 14 +21496 48822 5 +44190 46662 13 +50202 24007 13 +30969 3656 4 +6051 58368 10 +13137 51858 8 +14478 23049 14 +8658 18106 15 +401 49481 11 +5489 16647 10 +54130 59220 12 +55392 30026 16 +9187 31 14 +20218 45941 8 +32645 1158 10 +55787 59595 1 +58541 12852 12 +1857 7752 1 +26007 18248 5 +35558 39397 4 +20876 10705 8 +48116 28627 6 +30540 22970 7 +15658 6387 15 +48470 1564 11 +33589 31124 11 +23145 52940 12 +28150 4938 8 +12463 11342 4 +68 4384 8 +31861 28402 7 +8043 35466 7 +52990 47759 3 +2240 22904 10 +35295 35832 10 +28635 12082 9 +48219 34860 10 +39853 50861 10 +44490 6154 6 +10008 39298 9 +470 1284 10 +26742 30887 16 +1632 28090 10 +11381 38903 4 +297 47861 12 +53285 18719 13 +12729 49659 9 +35129 45025 12 +51232 18082 15 +33478 40760 4 +54044 18368 13 +55819 8431 9 +55797 34909 13 +32666 30017 7 +1428 49178 9 +42729 43748 11 +16487 33917 8 +56565 12626 8 +51886 15088 11 +29348 6770 12 +58708 56105 13 +23726 34483 8 +40285 33334 6 +2321 57476 18 +46733 52807 6 +24309 22436 8 +9256 22973 6 +16917 52867 9 +737 19524 8 +49372 57914 10 +57923 33550 13 +43500 16726 7 +23117 58167 9 +41211 4946 7 +48367 32008 7 +24677 39810 10 +59314 55943 15 +42618 25251 9 +40168 15340 11 +17267 396 12 +18116 44763 10 +12275 5042 16 +45196 49578 11 +23133 26953 9 +4269 6298 5 +43332 1713 9 +38864 41494 8 +44739 52982 10 +26344 47320 11 +55234 45464 10 +20540 50101 3 +19265 16111 4 +7085 37867 16 +54637 52836 4 +18424 39036 6 +44523 7488 12 +40681 10456 7 +36209 57857 6 +28875 27124 1 +57539 25149 17 +51490 33658 1 +55664 18756 9 +18255 4858 9 +41842 58090 13 +37905 39881 11 +38909 17125 2 +6900 39576 10 +46054 57358 2 +8522 3971 9 +30609 19506 7 +5882 18916 10 +19680 6205 11 +21206 33068 7 +56865 40585 10 +48401 15965 2 +1398 10947 7 +16701 2344 9 +21943 29416 9 +40682 10114 5 +53759 5969 9 +47408 42354 9 +3525 18219 5 +19721 6526 8 +37587 23577 15 +52729 27029 12 +28601 15016 11 +38702 28016 8 +43414 7616 14 +3771 26753 1 +20712 39986 9 +58913 23023 1 +54236 18606 1 +13110 53123 6 +35600 58479 2 +4936 51364 14 +49433 43307 10 +19323 50106 9 +50696 32665 3 +35117 39194 5 +9166 30689 6 +53103 47970 4 +49713 37246 6 +13460 42723 11 +42038 18520 6 +39887 24770 9 +23733 25307 6 +56451 55241 15 +3154 17987 8 +13915 44642 12 +55197 53404 4 +28498 25104 14 +12925 59051 9 +23732 44161 9 +48580 15839 15 +32901 46971 5 +8358 15942 13 +15380 21066 1 +122 38281 5 +35523 47969 10 +6108 32447 2 +24045 52784 7 +4208 48359 8 +5030 55325 13 +32655 19701 13 +665 22523 15 +2825 29597 13 +50206 27302 10 +36703 37693 13 +19174 11398 13 +4207 32548 12 +16000 26643 17 +53162 31711 5 +24645 51439 1 +58856 12600 17 +22801 32829 9 +31722 28294 5 +775 22031 9 +4829 11088 11 +19577 32455 15 +5594 17222 16 +50348 6243 10 +58834 11142 13 +21872 52250 17 +59675 32230 8 +44816 19274 11 +14700 43607 11 +39245 5878 13 +42844 12933 10 +15474 14624 6 +41320 54109 4 +21314 56333 1 +45754 37834 8 +30992 24148 0 +39254 32798 11 +54368 41906 4 +59458 22533 10 +9639 48155 11 +38616 3741 6 +23772 14649 9 +32305 38981 7 +37628 12090 14 +46154 33959 16 +18733 26677 15 +338 17347 13 +51995 18560 10 +33457 51754 9 +32474 9408 9 +346 5124 13 +12574 22746 10 +46874 25953 7 +31485 48547 7 +7881 12597 10 +50097 16795 15 +57794 23163 17 +11550 56293 13 +31257 42889 12 +56311 58362 4 +52607 20840 3 +2469 21687 4 +4752 45375 7 +56555 34238 7 +13330 14275 5 +10181 36111 12 +57764 41642 12 +8728 37105 8 +18867 18160 11 +12160 25374 15 +42339 2228 4 +47203 10397 12 +15614 5659 4 +34790 55288 9 +33388 50639 16 +47781 7649 3 +45238 17957 12 +55690 4453 4 +22841 42827 14 +24082 43631 9 +10655 39610 14 +3581 47409 10 +21284 20249 6 +14104 8826 13 +58305 46094 10 +3190 9556 15 +55362 5078 14 +57457 34440 3 +27897 24245 2 +27887 614 11 +34839 24108 8 +9244 3423 13 +37984 14024 9 +31601 39572 6 +2702 53701 17 +2496 25312 6 +16754 46018 10 +43717 4797 11 +48176 32338 1 +58545 15320 10 +41867 59891 8 +9961 31287 11 +2055 28224 10 +56337 11843 11 +12905 16614 7 +47145 28632 10 +21705 5109 13 +1410 48390 10 +37083 44273 4 +23739 13480 9 +54000 21080 8 +30674 2457 9 +30474 50163 15 +54330 56191 5 +40179 45942 0 +428 41395 18 +15536 2498 7 +31106 20071 6 +2998 58630 5 +37479 35038 16 +6105 40411 8 +55837 30000 3 +53360 14102 0 +49447 53562 9 +5034 3345 9 +20690 26908 16 +6918 42731 10 +13015 39315 10 +44285 39389 17 +17570 33815 14 +9317 56001 10 +35605 45995 12 +25657 16904 9 +33045 8921 3 +31337 42686 11 +46750 21945 6 +57186 52669 7 +25496 12031 8 +3044 40994 18 +50768 28320 11 +15025 47804 8 +15103 1459 9 +3729 19736 4 +3533 48310 13 +25726 14768 11 +53079 16875 12 +34189 19183 13 +49115 917 4 +22155 10088 12 +33305 45372 7 +43565 4183 11 +41491 23996 8 +28567 47761 8 +18068 55745 6 +13064 35518 14 +7958 43574 9 +19141 15433 16 +50737 35678 6 +5833 30430 2 +42077 21876 16 +31854 43648 14 +1102 21209 3 +29649 4296 12 +9345 32781 8 +57893 27742 8 +48316 58199 12 +55960 49685 3 +56349 32885 4 +54318 16149 11 +9048 48908 1 +51447 43558 9 +53814 50950 3 +59010 58787 9 +36765 33620 3 +57500 28017 3 +23799 29752 12 +52971 43278 6 +55092 45618 16 +46678 27810 4 +44906 14898 10 +34792 57194 4 +56444 7382 5 +28160 15007 3 +24342 3904 15 +23579 29511 8 +52941 36214 5 +54746 6703 11 +56697 47038 11 +50113 15562 15 +26876 44692 5 +10291 52484 9 +35393 40404 5 +36249 38515 13 +13446 29141 8 +55153 37710 16 +54596 49783 13 +53111 40615 7 +37887 3405 16 +42756 15037 12 +11569 58830 6 +26734 46987 16 +16529 6544 11 +49480 10957 6 +42610 26063 7 +13104 20375 6 +25199 19839 5 +23650 35708 8 +56685 24276 8 +33746 18635 17 +25257 34857 8 +37795 46680 3 +4361 4634 12 +2961 51135 7 +42652 59153 6 +29940 43873 14 +13146 48866 10 +48496 6912 7 +11786 34097 7 +24040 25265 9 +51324 42268 9 +59435 27004 16 +9086 3807 15 +8453 58813 6 +14570 4632 9 +16806 7080 12 +24998 23635 18 +39977 30852 2 +24609 10750 6 +32826 45929 8 +21507 43050 2 +14411 14602 8 +12227 42264 7 +34717 28883 8 +6586 29356 4 +31917 33235 14 +39521 48207 9 +36994 38482 1 +31573 9895 10 +14398 21304 11 +44044 56950 9 +7638 44006 13 +55830 58888 8 +41886 44399 4 +51565 50253 11 +26853 37802 1 +53639 24815 9 +25096 25323 14 +10973 10678 11 +19871 38039 1 +45680 4511 10 +1427 49248 4 +37849 2815 10 +46091 14023 7 +51780 24601 8 +18006 377 14 +58690 48693 15 +15929 50254 8 +50617 36954 7 +12844 23698 9 +30704 48104 17 +35414 51211 4 +7723 52031 5 +59072 52384 12 +59492 21270 9 +49993 49243 2 +13084 14260 10 +54492 52630 10 +44635 47950 9 +26510 57546 11 +54761 27380 7 +50003 57508 15 +14882 1703 5 +26563 35592 7 +36310 14799 11 +44629 4882 6 +27180 23868 13 +50319 26804 12 +55696 41368 8 +35524 41031 10 +25866 13772 10 +21125 13894 11 +52404 45044 12 +8540 11314 4 +56644 45771 7 +29854 31560 11 +24748 59754 9 +13583 36595 3 +31533 53467 8 +41680 3215 7 +1859 37930 8 +3791 48466 6 +7764 10261 1 +47244 43772 14 +22080 15848 12 +41877 33980 6 +35142 16693 7 +17757 39392 4 +27309 15588 3 +9628 59481 5 +27844 26916 9 +27058 29608 10 +10987 31379 8 +38247 37165 16 +11487 41333 7 +40380 37334 7 +24747 34815 6 +44742 50049 10 +3024 37928 3 +54091 41635 5 +41538 11358 7 +1937 59805 9 +25278 46767 8 +5688 53477 9 +54733 1341 9 +26018 49453 13 +26017 9302 8 +8059 2763 18 +3325 44722 12 +54567 48771 13 +57997 49548 9 +4546 30685 12 +41541 36854 10 +8590 13504 7 +15693 43335 17 +51828 21815 3 +4645 6220 9 +29641 17873 5 +59917 40608 18 +53109 19582 12 +12077 13411 4 +46047 22264 7 +29310 40597 7 +19642 12780 10 +32603 39402 6 +16559 38966 12 +4305 51479 8 +51140 20079 17 +24680 34970 10 +50983 59957 8 +57114 40936 6 +25502 58889 10 +10364 3724 5 +42126 23293 2 +4048 50969 8 +27220 34562 7 +30918 33450 11 +3703 1054 8 +4326 52304 16 +51317 39738 6 +14293 51346 8 +35477 17655 8 +48241 23382 8 +17390 29196 8 +52331 47291 3 +52755 3799 4 +53686 8255 9 +17176 36358 12 +24757 9593 14 +53811 46562 8 +56929 40589 2 +10534 37623 10 +9413 5216 5 +57160 9852 9 +54428 56905 10 +574 44233 7 +3957 33944 13 +39105 40324 14 +27063 52893 5 +52336 55279 1 +38212 22828 1 +39907 12645 6 +34615 345 10 +18477 19758 6 +26185 32946 9 +19833 56920 9 +18396 44475 10 +11306 4934 8 +7215 9807 13 +48085 51896 4 +634 59818 10 +38897 50670 7 +25608 18758 7 +45804 4566 8 +29464 3140 10 +12020 44203 8 +4260 47250 14 +47894 28866 13 +34377 46988 17 +54071 3689 9 +27611 56964 15 +5763 30745 12 +45504 7595 5 +14818 22412 10 +59647 28505 4 +31219 39746 7 +52656 41868 7 +37589 50247 7 +6021 8896 1 +12828 22930 5 +12036 42960 10 +24184 55876 9 +39975 38276 1 +44509 41770 9 +42509 35771 9 +27922 30780 7 +25095 27358 15 +57485 40572 10 +1772 58239 15 +11152 59415 3 +57144 46304 5 +41024 6772 12 +47159 54940 11 +21662 35364 15 +53499 53197 12 +6516 14951 8 +9433 16953 16 +29260 26915 7 +8533 20272 6 +30196 1270 2 +23722 8852 7 +14895 2676 16 +49582 812 11 +48730 38362 9 +44348 47031 9 +2515 21920 11 +43248 59546 14 +18079 37074 7 +55403 2552 6 +29873 29840 1 +40928 47052 16 +51842 17128 17 +4284 587 1 +4278 27555 6 +43811 7693 1 +27355 14066 10 +49672 35634 5 +17167 45822 12 +7572 11288 9 +11706 30706 5 +30525 22704 13 +3273 27093 10 +49592 32149 10 +59588 57361 7 +37548 50805 12 +25801 44107 18 +54571 47082 18 +27068 53528 5 +49842 32417 14 +2019 41991 6 +30184 12669 18 +32790 42368 10 +29339 56408 13 +20076 29166 10 +56921 3970 12 +48127 17626 7 +29418 43620 10 +48781 46799 10 +22727 12380 10 +53218 27173 5 +16080 1499 8 +36308 31152 12 +52828 50631 4 +54137 24219 11 +51798 13978 10 +1841 2215 10 +11713 52734 8 +19608 17651 9 +28173 22935 9 +17287 24126 7 +2471 10983 10 +55359 56053 7 +16140 14177 5 +44421 14514 12 +22017 29667 8 +28856 29524 13 +16269 43367 2 +10190 55649 9 +35005 3298 15 +56028 51408 13 +52806 19520 10 +11767 39595 7 +40916 13521 7 +10418 23717 14 +34848 57650 2 +52922 38614 3 +32296 22380 6 +41822 40624 8 +39549 47601 10 +23053 25173 7 +47967 45714 10 +12411 35756 7 +17150 57649 8 +20 49843 8 +10191 51615 12 +36250 29231 11 +29606 42714 10 +37036 14043 3 +53448 19129 3 +13653 6959 7 +23601 25936 5 +59721 13607 5 +50284 4968 13 +28764 33518 13 +24839 54665 9 +15348 16312 10 +55959 58436 12 +51418 44853 9 +36666 20589 10 +42767 38522 7 +57119 11730 13 +32947 1807 3 +23160 57176 1 +26249 31788 7 +54701 40995 10 +17854 10974 1 +44771 31824 11 +17680 51710 6 +41883 29571 8 +40257 54899 7 +1999 40048 8 +52835 22111 2 +48341 20655 9 +40534 4290 10 +47544 15528 12 +27263 32424 7 +35502 10179 7 +1977 37331 10 +52124 11618 10 +4216 3237 1 +59028 18824 8 +15302 42361 15 +19307 44740 5 +4054 36944 14 +2390 58261 9 +28297 57048 15 +724 4697 9 +29123 39236 4 +14944 50728 3 +31247 10010 2 +10867 51142 12 +48991 39084 3 +25430 58521 6 +42962 10403 5 +59912 4388 9 +14963 48159 15 +44020 37534 12 +28019 4317 8 +7524 45509 4 +45210 1217 11 +39360 50036 0 +20735 44262 14 +34698 50167 8 +22190 22566 11 +57749 30955 1 +46145 1910 4 +38893 52640 6 +17436 51482 9 +37980 15135 1 +397 52779 8 +46088 27400 11 +36390 5840 7 +7887 36542 9 +57713 30431 7 +37407 55699 12 +20400 11260 8 +32547 37142 11 +23355 26364 5 +9285 40344 15 +1006 1413 9 +10200 56509 2 +20034 16418 6 +57864 19779 5 +48253 39542 2 +44042 37637 16 +58230 6475 8 +7374 24759 14 +34996 41917 8 +50177 1711 11 +43795 36886 15 +45547 36487 10 +47452 13266 1 +49745 8056 9 +44158 21549 9 +12282 28087 17 +21756 59700 13 +25796 15869 11 +56802 47343 10 +7003 744 9 +44726 37335 7 +40129 57645 2 +21133 56776 10 +30619 53174 7 +27320 38536 9 +41005 53901 11 +16134 28681 4 +424 50623 15 +56893 387 11 +42413 45986 8 +28497 52230 15 +43582 55791 9 +37851 57845 8 +20164 9466 12 +46949 53278 5 +8971 12289 14 +23224 29529 16 +30547 48823 6 +49826 14874 4 +9844 7926 14 +54837 36607 11 +50533 10515 13 +59353 820 7 +57391 5553 9 +24740 46830 10 +50448 4617 13 +33409 2739 10 +29005 37025 11 +13272 18215 3 +6624 45733 8 +19575 34616 12 +58617 56907 8 +41826 47841 4 +51998 55345 3 +45541 48287 1 +36155 55377 9 +43643 19989 13 +26489 37293 10 +19843 20333 11 +50311 38786 4 +10616 16235 4 +38044 18342 13 +56197 13719 3 +58962 4620 8 +54434 26482 7 +6423 54867 4 +13103 32888 15 +43931 30811 8 +30595 22023 5 +20465 26755 8 +10940 37986 11 +32977 12876 12 +49132 30925 7 +2996 14131 0 +12176 28667 7 +8786 4595 6 +41925 49974 4 +35269 35764 10 +38937 43577 3 +45134 21587 12 +53999 24574 13 +49499 22026 3 +6648 26850 2 +2262 39934 12 +52419 2340 5 +28999 33384 15 +36683 33038 13 +21895 50847 6 +57267 59669 14 +15795 47911 6 +39 36885 11 +45834 58042 11 +32484 42585 6 +6083 49501 5 +47525 37503 11 +43079 11084 4 +20891 32630 8 +677 32817 10 +26231 55175 9 +49689 29046 9 +11872 53214 15 +27641 5940 11 +45416 47789 14 +11700 18014 10 +15707 32357 14 +57610 28502 7 +17049 27967 1 +12867 14172 10 +45877 44955 8 +30601 17439 10 +28127 49831 14 +41046 37466 17 +44761 32237 4 +40119 17070 4 +9896 39421 11 +47674 27201 5 +37016 59816 7 +28831 55096 7 +37002 46025 17 +53259 36917 5 +55103 38145 6 +30299 15195 10 +33299 39053 10 +42902 9682 5 +16974 16239 11 +729 36649 5 +6580 11727 10 +31306 3854 15 +39755 1252 1 +13342 57318 16 +43017 13665 8 +40709 57094 5 +48807 19753 1 +59386 51904 12 +59970 46631 10 +16687 22467 14 +19888 20129 14 +3149 40583 10 +27521 50560 12 +41835 3985 8 +31875 57065 11 +28549 58503 9 +55476 58982 7 +42802 41611 17 +47657 5304 10 +13576 26306 6 +36933 8599 3 +30586 36304 0 +15113 17678 11 +43483 3395 9 +8768 48067 8 +5433 57782 12 +41247 41157 7 +34244 33263 3 +23763 18213 7 +51607 45750 12 +38236 38539 12 +2741 6680 11 +41659 52153 8 +29410 38079 9 +36758 52172 12 +32831 39734 7 +12676 59421 7 +189 45776 9 +10614 56376 13 +29063 31873 6 +20162 53648 15 +44758 41852 3 +10549 31393 4 +32178 31645 10 +17285 53917 0 +6281 9057 14 +40531 4953 10 +22522 13697 4 +44485 28182 15 +29268 2977 6 +19452 7538 10 +30427 38029 2 +58140 37127 16 +26159 29877 14 +43044 19750 3 +15791 10931 7 +14687 23969 16 +44386 59708 8 +29749 48674 7 +5120 48698 2 +57618 14369 10 +17025 27958 8 +13055 17799 17 +16002 4144 8 +38845 41082 3 +14686 38520 6 +29507 59427 7 +20214 16554 15 +37227 22368 6 +48282 48758 13 +34358 25170 4 +16511 13006 6 +8527 44354 6 +55891 43658 7 +13122 33553 13 +18944 13334 10 +16325 46342 2 +37206 5846 15 +51612 9513 12 +49291 33451 13 +37039 53833 9 +38087 17749 13 +41439 13792 14 +39335 39303 9 +54913 31099 10 +5954 33486 10 +58923 24608 7 +19997 2183 4 +47536 30244 8 +15964 48191 3 +19876 35905 2 +51267 28407 11 +35759 58513 7 +49760 55318 9 +25734 57796 10 +40864 921 6 +13578 26031 10 +576 21738 8 +12776 22322 3 +17554 55841 7 +44571 28519 6 +11531 54852 6 +32025 15468 10 +45629 3408 12 +1012 46853 4 +47527 34785 9 +3200 8753 10 +53134 47237 13 +5405 12977 12 +11437 49387 7 +33718 29021 9 +46951 24298 6 +16205 38538 8 +19380 39019 10 +37202 12946 17 +54026 28238 10 +50062 25590 4 +14797 17712 5 +13811 21178 6 +26539 31830 1 +41788 39240 10 +59615 27445 0 +25853 46714 10 +52086 24447 6 +3878 28508 7 +10300 37191 3 +17427 3958 17 +31327 59544 10 +12476 36835 8 +26309 9899 9 +101 28948 11 +18744 15227 12 +44302 36503 10 +36803 56740 7 +37652 27811 3 +9783 9568 10 +8901 47112 6 +25446 49708 14 +42206 5764 6 +55121 50727 1 +58146 7766 3 +27192 5656 4 +39008 44527 10 +38051 9902 10 +2047 49345 5 +19801 4385 7 +41422 29555 14 +22787 46035 7 +56189 45299 5 +16071 46708 5 +30171 21445 10 +51803 19625 15 +35341 29185 12 +34407 48634 12 +48430 46336 15 +49223 49320 16 +28546 22882 0 +31349 1778 6 +24430 13344 2 +58916 34372 8 +42575 39905 9 +28922 34923 2 +3234 25747 6 +5519 21171 8 +44933 38542 2 +40705 24159 9 +19220 59201 14 +52396 57130 2 +15933 26811 8 +22638 59931 9 +911 10544 14 +1822 34230 8 +17353 56461 7 +49664 45018 6 +19302 36615 10 +10272 53736 9 +50572 48670 1 +11483 50663 15 +41508 9442 10 +56723 57932 7 +12252 28403 7 +23264 18868 5 +33495 34379 9 +22742 50934 8 +16828 15584 17 +7873 2924 18 +45908 9670 3 +28714 32000 8 +50077 4435 9 +57000 40469 9 +16384 30024 11 +18156 24080 9 +31735 24927 12 +38108 20754 7 +34146 18806 5 +47943 32113 12 +23456 11542 13 +18757 40631 16 +40653 45797 7 +1570 33763 10 +13735 33584 8 +52148 39813 16 +33053 58430 11 +3046 17216 8 +56186 21772 12 +22379 25315 10 +1046 8396 7 +36403 29719 9 +8885 35184 6 +23431 45639 17 +28919 26228 9 +10588 45341 11 +45357 28563 11 +48976 18528 10 +43805 30876 9 +39299 6203 10 +14943 12318 10 +51151 19810 6 +2963 11501 4 +43381 31230 12 +18640 5759 7 +56995 1031 4 +16 16934 11 +27240 41618 11 +440 35322 6 +51563 16735 2 +54868 53664 6 +14197 34342 13 +9306 47838 12 +36319 22958 11 +37108 42312 14 +4957 37117 8 +26658 18089 10 +27708 53939 7 +55854 59730 7 +51611 24358 11 +15970 53352 14 +23816 49516 16 +23210 37093 7 +29340 53960 7 +9128 7155 18 +31440 11296 11 +49294 37226 8 +14736 35383 11 +15865 24952 1 +14699 23439 12 +38634 43875 9 +19161 28775 11 +2424 33939 7 +16822 22211 11 +29087 17106 1 +14480 17988 11 +49965 9230 9 +35482 50994 11 +42828 32173 14 +4397 17258 8 +16123 13164 2 +14045 49647 7 +28656 49489 10 +50440 9763 12 +59111 28454 11 +1291 59150 10 +39822 48098 16 +14042 3528 18 +12334 1051 4 +31262 8932 9 +27241 57964 10 +13165 53237 7 +9527 24465 3 +24264 45269 9 +29103 27501 8 +11962 27457 5 +18570 41246 10 +52974 9787 10 +2578 20838 5 +55389 29317 11 +4464 32198 9 +13388 32051 12 +43718 11456 14 +25247 41731 14 +14540 50567 11 +30650 9541 7 +20638 41908 10 +18662 19598 3 +48013 34612 5 +20850 37056 7 +10706 55201 18 +7097 8167 10 +40401 49154 4 +34594 11074 17 +9336 56139 8 +14566 10143 12 +6208 58217 6 +35179 34436 6 +56500 5151 9 +39956 47848 5 +32807 42853 10 +28842 13873 2 +53713 20407 4 +14237 57402 9 +15190 8463 13 +53980 45379 9 +10521 45752 8 +30730 51519 5 +44938 19961 9 +54715 54157 8 +24239 27376 9 +51150 2037 5 +50867 11045 9 +43634 58297 6 +47578 35766 7 +8186 52219 15 +18581 17102 4 +5808 47863 9 +36275 46074 14 +23435 34363 7 +45514 25375 15 +21083 40258 12 +43391 57298 2 +45717 33517 16 +17927 23950 11 +54926 11564 15 +21980 30374 11 +48980 59443 18 +56782 3978 9 +1178 7205 4 +58329 33538 6 +3998 43384 16 +7449 9 9 +5146 41406 7 +18199 34694 15 +44970 33071 10 +44751 17200 4 +38849 37909 16 +42139 5790 6 +1526 14890 5 +56612 19679 7 +43520 51630 9 +5400 22877 2 +2441 45455 4 +56545 17544 11 +32072 2812 10 +15139 133 12 +30902 339 9 +46299 9544 8 +34354 56549 10 +28646 22759 8 +23681 23701 11 +12403 2046 11 +55768 51603 2 +5661 21315 16 +10905 47873 13 +18322 6589 16 +55033 38714 5 +17599 22295 5 +2694 49034 4 +52274 15286 12 +23930 14851 11 +51822 20121 8 +10495 29793 15 +27084 27289 3 +1297 13673 9 +38604 34220 11 +12432 31192 16 +27739 37529 2 +46177 10220 7 +14140 14305 16 +20273 56686 7 +4192 7098 14 +10561 55704 10 +39818 46667 6 +4405 28169 3 +48101 21337 14 +20653 7891 12 +21325 38253 7 +40819 39989 8 +3180 1649 7 +29195 6941 13 +19665 14809 10 +37368 34191 10 +51419 47205 2 +39781 47276 13 +43305 39221 12 +7306 3668 11 +33533 19325 8 +50761 5091 10 +5483 39283 3 +50863 15512 15 +13112 17044 8 +29135 51860 8 +41088 25513 8 +4055 7681 12 +31188 23843 10 +15713 5122 5 +17113 14448 14 +29306 35792 9 +37774 41464 16 +32329 44403 17 +44456 38336 7 +11242 48858 8 +44318 6287 13 +44174 40880 4 +612 29274 1 +48426 50523 3 +32248 12400 13 +16825 14031 9 +31638 58364 6 +35506 17277 14 +15689 2429 8 +778 35742 5 +35270 51709 9 +1299 34044 11 +58937 43710 10 +15976 971 14 +52979 49719 11 +24118 1140 4 +59678 34141 4 +26595 47937 6 +31590 45745 7 +20873 4006 16 +22439 28047 17 +25769 2238 13 +30078 17435 5 +1942 46279 4 +55127 15747 4 +15632 49401 7 +23678 30434 7 +35412 35870 7 +19453 45708 16 +28759 41927 3 +49437 58837 9 +38412 42930 3 +41878 39095 3 +58093 35233 15 +10260 53171 10 +7961 50733 9 +32102 21712 14 +29375 24185 10 +20188 3238 18 +36678 31940 13 +30762 1168 2 +31091 38771 11 +40569 35837 9 +30124 30767 10 +20981 3612 2 +59629 6380 5 +52054 5440 11 +58253 54357 4 +41009 23906 12 +38413 28377 7 +39964 14904 9 +13123 54367 15 +38575 42718 16 +9291 52921 5 +35856 38732 4 +56957 16431 6 +16247 14278 7 +57527 44944 11 +3328 43675 4 +25365 19831 12 +24812 50232 6 +45374 43871 9 +41681 2229 16 +47814 17644 13 +8118 30604 15 +55844 44166 5 +33256 42913 9 +47242 3103 8 +7303 40205 4 +54472 13584 8 +9576 25132 14 +11708 19995 12 +26659 54598 12 +901 50674 8 +47045 5560 6 +3585 49834 2 +272 2153 10 +37381 30146 5 +1000 15784 4 +1726 17415 10 +40007 30245 8 +8188 10513 11 +31194 3654 6 +52816 6878 10 +10183 26156 12 +22300 25184 11 +7189 47675 11 +12822 16514 9 +17725 4431 6 +1739 30166 14 +19597 7448 14 +37019 6388 10 +11650 12098 11 +53293 58554 6 +28898 36356 7 +27872 46628 7 +34579 57906 6 +59562 19699 14 +24985 52898 2 +19211 37013 4 +43567 58452 3 +18052 38659 12 +25136 36391 2 +11333 38644 9 +8910 11255 11 +10984 33272 9 +1465 48935 12 +8957 24021 8 +1606 10245 0 +4715 57895 10 +14422 55720 8 +17375 12666 8 +42447 53882 14 +23645 55803 16 +42637 55577 4 +26081 878 6 +35697 47668 1 +24357 31355 9 +17633 21527 6 +1887 15402 10 +6690 38755 9 +12554 56265 3 +36103 32768 5 +34722 58718 8 +18774 1466 14 +425 38992 12 +40837 12156 9 +41849 34177 6 +39642 45427 17 +3297 59632 12 +21011 16936 11 +25812 24963 7 +22443 35343 3 +24641 40557 15 +46482 4763 7 +53029 10305 11 +2050 28218 6 +45250 45498 7 +18952 5447 15 +31000 10405 9 +56164 20335 10 +9713 57597 11 +47125 54054 17 +41882 32739 14 +56151 31510 15 +30846 10945 6 +11683 54069 9 +19798 25122 2 +37448 51978 5 +111 14340 5 +29624 28020 6 +58186 44581 12 +7795 20313 9 +24670 17083 13 +40474 55613 12 +6555 42917 10 +31411 47058 10 +22101 31723 8 +27791 20461 3 +33932 53267 13 +54625 29566 12 +12183 36757 12 +45349 40789 3 +1170 26118 9 +373 44899 5 +40843 3245 6 +8344 59903 6 +15922 15598 15 +43639 57273 6 +13155 8046 0 +15282 39931 9 +30054 51320 4 +45337 48014 12 +6468 13323 9 +17310 35377 15 +19611 10759 14 +46503 44917 4 +19326 24671 8 +58115 694 14 +53078 42722 11 +22789 55732 9 +13422 14225 16 +34176 24208 10 +57904 59923 7 +19964 6862 13 +50845 34726 11 +6077 1754 7 +13379 24356 4 +22748 37249 6 +35091 34766 10 +30322 42433 8 +19746 40144 10 +53938 36473 11 +33134 56116 12 +38947 25356 14 +41710 38708 7 +39527 53533 0 +43156 1095 5 +48039 16037 4 +13252 48592 5 +15782 23758 14 +42252 32546 11 +4184 47128 9 +42153 52659 2 +28612 50132 6 +18458 22032 12 +24119 31473 8 +18871 13664 11 +37655 48903 6 +38667 26027 2 +3658 38037 11 +51501 7954 8 +43433 41742 7 +14795 30677 14 +36478 6844 11 +58936 20985 5 +47259 44850 5 +39615 37935 9 +32202 14520 6 +58567 36657 2 +21327 53581 10 +45818 35566 8 +34733 59830 11 +17229 51393 15 +2403 37423 7 +5802 22900 8 +17541 17699 4 +33043 1141 8 +26121 2620 7 +33512 58107 8 +58993 37145 10 +15429 28569 5 +48762 25068 13 +1539 44009 7 +7816 32406 1 +5486 26928 9 +49009 30520 11 +14600 51126 14 +32846 7046 3 +58667 41697 10 +336 52975 6 +40600 5524 10 +47755 21101 10 +8258 46267 2 +42900 44780 17 +51723 57733 8 +41958 51002 7 +37960 48613 7 +24659 33838 16 +45007 27109 9 +21603 38828 8 +11060 55424 4 +44621 4391 13 +16623 18099 10 +53164 18230 9 +58162 51190 3 +55884 59141 15 +10836 8180 7 +45946 32898 12 +31297 34818 9 +32905 38901 2 +20570 250 6 +28177 23063 14 +36669 43630 3 +8798 30280 12 +7339 43011 3 +4954 3504 8 +50320 18245 9 +11626 6854 15 +45203 27952 7 +51335 28144 15 +14896 29924 13 +5060 47404 11 +19791 22982 13 +35328 34131 3 +8409 52189 11 +32994 52852 10 +27306 53496 15 +38533 58672 6 +5567 19589 8 +53626 34228 7 +51550 44605 8 +23887 43030 3 +11143 47290 3 +1616 55833 10 +33374 28767 5 +43960 37030 8 +30042 38143 7 +55038 44592 12 +25353 49029 6 +53871 47831 9 +8115 10976 9 +38420 10719 9 +33714 52943 13 +16122 19418 4 +38141 35660 1 +12711 13720 13 +50291 30958 1 +444 26619 2 +7765 41739 4 +8153 25882 9 +41524 28141 6 +48889 17773 13 +41485 26245 2 +19954 24368 7 +12659 26918 12 +54433 46823 1 +14983 9811 15 +11698 43544 18 +19044 1844 10 +6216 28964 4 +36618 2554 6 +53800 7980 3 +33253 23945 9 +45727 40318 5 +18391 227 16 +21197 5095 4 +37100 24799 12 +40575 20893 12 +50071 47053 13 +16206 52021 4 +40241 29057 1 +8079 645 10 +13819 15192 14 +6355 56619 12 +43318 9253 8 +11878 25234 10 +887 14662 18 +53325 44863 12 +2400 53649 12 +52907 23501 4 +37931 35495 11 +20246 57051 9 +9983 51592 9 +48078 49523 12 +34915 30034 6 +467 21151 9 +29570 53919 1 +2686 53311 10 +59657 57205 6 +37378 35736 7 +51240 35486 12 +56911 33619 14 +32685 14572 7 +5127 17833 10 +14573 16339 15 +25952 2983 4 +18169 34957 12 +32891 58998 15 +17490 3515 14 +30643 12121 11 +34269 50783 8 +6408 27430 10 +11073 13916 4 +41703 2886 9 +30 21302 12 +19056 38761 11 +39345 13398 8 +11560 5500 3 +18541 1811 10 +41973 10039 15 +14388 10508 4 +17418 28263 4 +7400 6260 12 +18101 36159 12 +56605 5885 3 +33470 28444 10 +30268 56475 11 +15042 40546 5 +59590 13127 8 +21312 25294 10 +10047 44810 14 +11190 47322 17 +57417 45497 9 +12863 11895 8 +12354 7480 11 +40713 10434 10 +33531 48445 12 +36373 6748 2 +36483 52277 8 +19055 3541 4 +15152 40477 10 +30286 34945 8 +15435 34268 4 +22975 53336 12 +43644 29020 9 +12521 35078 5 +21490 12001 8 +35411 48229 7 +38965 30058 1 +41328 58311 10 +29871 24583 12 +20910 25061 3 +30723 13572 16 +37207 4285 8 +4263 15874 8 +129 32715 15 +17733 8797 10 +27886 24840 1 +7862 50329 12 +26882 14543 12 +3282 58947 11 +55262 38099 1 +14014 350 17 +51624 11427 12 +32048 47795 10 +23396 4472 8 +44672 21320 5 +27853 40183 9 +32801 7289 10 +6782 30182 11 +33682 26208 12 +36096 31449 10 +48958 10572 14 +3415 36570 9 +40771 6036 15 +4950 16723 5 +26825 30104 4 +37138 4103 9 +29053 33664 16 +8374 16907 3 +18876 18388 13 +5602 58136 8 +1805 30835 7 +3134 35713 10 +11957 58943 0 +20104 21704 13 +10321 40958 2 +50005 5268 4 +40472 5455 11 +4089 11920 1 +58407 47695 13 +13825 41235 9 +29779 42688 12 +13355 511 14 +15033 41349 17 +10444 34425 10 +6531 29761 5 +45075 12633 9 +20946 23175 7 +28709 52868 4 +42028 48297 10 +32031 50369 6 +45576 43671 9 +23504 32444 3 +38610 6556 9 +19906 9712 10 +31588 3649 15 +55824 21995 12 +29530 46975 4 +47717 26587 8 +4604 54049 13 +54999 2435 0 +50921 36247 9 +27797 28372 7 +49449 50230 8 +3554 25542 8 +7044 40107 7 +44570 14694 9 +44644 61 10 +3133 7931 9 +24213 6075 3 +19895 11350 14 +2865 28755 7 +12103 18653 9 +9457 5061 6 +47354 59688 3 +34426 5985 3 +32273 41346 6 +7509 20764 13 +13349 21235 10 +25115 26527 16 +38056 567 8 +39591 12222 6 +16499 28432 13 +123 8535 15 +48599 6734 12 +12130 48043 10 +47044 20038 9 +2801 12107 4 +8061 42387 9 +56717 53891 2 +7167 456 15 +50491 23268 5 +56520 23025 8 +41216 7333 6 +33722 19072 3 +43523 33705 6 +38763 1879 8 +48627 21263 4 +48570 21886 10 +47095 31479 11 +56292 27976 16 +56799 9854 11 +11608 3748 3 +47756 58206 0 +54911 21528 6 +39650 7204 10 +45849 19967 11 +12638 46525 8 +28099 28796 4 +39996 30512 6 +50868 59953 14 +56439 4147 15 +28959 33344 11 +8963 25703 2 +14437 6570 7 +51958 27350 13 +32772 39655 6 +38438 59155 2 +16717 49468 16 +56276 13802 11 +45743 23263 9 +26082 13523 11 +13179 7899 9 +46740 34289 3 +47872 49495 12 +29178 28471 10 +2495 3606 4 +20172 27175 10 +46404 56319 11 +54813 41478 6 +12816 30357 12 +7786 28079 0 +33178 18605 12 +21949 13182 12 +4536 31460 13 +28155 43723 9 +22885 4244 13 +30769 50815 5 +32561 50418 8 +3048 34467 4 +33182 28392 12 +47236 58761 10 +18989 50485 0 +26683 56211 15 +57549 26464 12 +15284 39287 9 +43430 13239 5 +38502 39401 14 +58740 41277 10 +19172 40619 10 +41232 59983 9 +43806 28250 3 +47243 44813 2 +5251 25317 13 +24187 35897 9 +44150 22090 14 +25089 1825 9 +22270 40492 6 +28156 7782 4 +56588 39558 11 +43068 56532 8 +23692 42302 8 +35721 57925 9 +10828 46463 9 +38381 4043 10 +53379 38975 10 +9209 37325 8 +27131 42606 9 +45799 23281 5 +24098 7540 10 +16540 59704 0 +45562 14998 6 +27777 50702 13 +11908 34339 17 +9450 3563 10 +25562 50459 17 +10184 58276 10 +6657 16866 6 +51049 49802 10 +15621 31906 8 +34675 22896 3 +11015 42696 18 +13216 55225 5 +4164 51605 12 +24100 55480 12 +48534 53712 4 +8766 45786 8 +41846 15809 5 +40123 29851 6 +55332 54216 12 +42550 12296 16 +19210 14433 6 +549 57103 6 +15999 34221 5 +29728 9641 14 +4689 38871 13 +45521 10158 9 +39728 14935 6 +54742 38529 7 +37798 18011 6 +56457 16755 6 +17016 58046 13 +5743 38200 8 +43946 58724 11 +32544 7370 10 +5580 44826 4 +47480 51088 7 +46400 11587 7 +29088 48901 4 +38500 45800 13 +54614 22288 1 +21256 50189 4 +59552 4707 11 +14524 41587 11 +47722 29027 5 +12426 23752 9 +14615 3355 10 +18684 14846 3 +50662 32422 8 +35246 59230 9 +27395 1826 9 +6811 57180 7 +12747 46968 8 +1631 29937 3 +17793 37259 18 +51855 18558 14 +5740 24667 12 +46820 53529 12 +84 48213 10 +36299 11131 12 +34144 53368 11 +4621 5779 9 +24163 10793 7 +38002 38962 3 +49124 16066 8 +27036 48691 11 +16341 58668 9 +25066 35004 14 +49838 46117 9 +17426 48197 11 +47627 52480 11 +19444 25745 3 +40045 39317 4 +28200 28420 3 +31270 32608 13 +29935 13428 18 +26927 40250 11 +4045 13455 11 +1858 31816 15 +15518 33327 7 +5989 50175 7 +22991 37097 13 +33431 9060 14 +42514 43855 12 +11282 22227 7 +38406 54314 4 +55965 41062 12 +37777 22738 5 +25566 25488 9 +49277 27371 11 +28845 9365 6 +15576 44734 11 +5699 5514 8 +56301 35718 8 +32445 41786 10 +241 13505 11 +36074 5446 16 +17448 50948 6 +53526 26562 8 +48801 51022 16 +37565 4691 9 +15845 23833 10 +21717 27871 4 +52577 14183 14 +52107 23278 10 +31784 46763 1 +24374 22450 14 +8920 40371 17 +16982 51005 5 +8114 17959 16 +41953 18984 18 +47645 59506 18 +31647 29701 4 +16383 32552 16 +39969 35205 13 +11918 38567 13 +10072 24644 9 +57537 48269 9 +41884 29373 8 +59165 56361 2 +16648 39203 8 +18234 57011 9 +8393 4819 11 +18995 13274 10 +47958 47350 10 +5944 38058 7 +30802 3937 2 +3716 33128 11 +33170 21560 7 +55348 25130 7 +39562 15950 13 +18986 44848 6 +53842 46496 2 +16933 23519 15 +512 5960 9 +52904 21856 9 +18423 17109 9 +41013 25235 9 +27462 54442 5 +54294 21299 4 +16253 39571 18 +20583 39210 9 +21562 27422 14 +5217 31264 5 +48439 51957 2 +23608 34987 7 +4081 16817 7 +30460 27211 11 +20550 47381 7 +15291 4162 1 +33062 54206 13 +51012 3736 15 +23463 22145 15 +44281 35268 6 +23995 3780 9 +2579 46909 18 +37856 23956 4 +26345 39110 10 +17028 52289 1 +49088 35741 17 +6166 16076 10 +1558 35886 8 +7001 47594 10 +59331 8675 8 +16793 17352 6 +31055 34541 7 +7700 5198 10 +9651 56313 16 +16479 22333 8 +23767 22713 9 +5648 16001 3 +22640 7441 8 +6181 25915 4 +32002 10462 10 +11059 17550 16 +38441 29767 7 +1833 6818 14 +44469 36174 13 +18320 1830 13 +23387 45882 15 +55409 55371 8 +35820 49665 5 +45762 509 12 +8088 10823 1 +9634 55207 13 +43535 46499 2 +2557 30755 6 +7416 48747 18 +9297 35543 9 +51358 3580 12 +59425 54309 6 +31352 10960 9 +1480 36494 11 +50222 48512 6 +3874 9095 15 +299 20913 7 +22191 29497 6 +32813 49771 7 +13258 56332 8 +14648 3821 14 +10422 7258 17 +31709 11851 2 +51432 21048 9 +14732 13392 7 +3162 48742 7 +27519 23029 12 +39357 31621 16 +45526 30782 14 +41095 11807 7 +53593 21884 2 +48616 11212 18 +48259 5188 12 +52808 2198 9 +56094 3548 8 +11080 46626 13 +50063 52420 7 +1059 21026 11 +16689 31016 5 +55101 14603 6 +40131 21259 13 +30669 3464 3 +44432 4443 6 +9800 2675 8 +24704 26161 11 +28872 30096 11 +50683 45440 12 +8586 40008 14 +4612 17910 12 +18007 13594 8 +39151 54058 6 +57350 50982 10 +36032 7797 11 +31581 16741 8 +17710 53985 7 +40037 3887 9 +58703 32560 13 +14137 3838 4 +39451 55872 5 +14420 32802 7 +29422 5929 8 +2923 7952 15 +28143 19840 10 +23509 23027 17 +55189 11107 8 +2201 53957 2 +38091 37020 9 +9216 50792 11 +41190 14640 14 +24503 32940 10 +53190 40907 15 +54517 51221 13 +31428 5056 8 +41946 59026 6 +55487 25510 2 +36272 44487 8 +46602 18204 16 +40314 19209 1 +365 36816 10 +35825 30789 7 +40811 15559 3 +26012 48646 6 +38399 36852 6 +16991 52350 4 +27896 11375 6 +53733 54320 2 +5436 55537 10 +7436 15612 9 +35164 10738 13 +23464 30538 7 +38096 21005 12 +58862 33935 6 +13208 36920 12 +44801 18311 14 +7137 18184 9 +2437 17593 4 +23351 11822 7 +56172 23578 8 +55885 29066 12 +48388 46897 17 +22870 40622 9 +48110 2893 12 +59177 52485 10 +6955 39639 4 +38193 27890 9 +29220 17230 4 +44622 50075 8 +28512 53793 11 +49816 35714 12 +45158 493 4 +2389 45624 7 +7340 57058 8 +54258 4600 8 +20883 19864 15 +18513 49595 7 +32638 672 14 +50513 24771 9 +18663 27845 6 +17976 37574 9 +16918 33809 16 +14771 56490 3 +22226 56485 10 +33408 16101 15 +44918 34117 14 +14291 46118 8 +19730 19329 15 +25610 26474 15 +31170 1359 9 +16663 49469 12 +51590 49994 13 +13435 38383 12 +6106 42695 10 +14614 2606 8 +2547 25092 1 +33219 53227 7 +12855 23461 14 +23019 36687 7 +531 46298 13 +49488 15961 7 +2289 20628 9 +46692 1445 4 +40692 18155 4 +8001 11849 12 +4210 14296 10 +48524 42106 18 +39593 23532 10 +36180 8426 8 +19792 44560 8 +38952 31104 8 +24876 25232 10 +19553 28363 10 +54070 33802 9 +3749 53168 7 +15751 34725 3 +14522 5862 8 +13963 29150 12 +55962 8754 3 +27780 16324 16 +25452 26244 15 +56727 2643 15 +46588 2306 4 +36463 13730 2 +22364 53420 8 +7748 56465 3 +6444 8278 4 +8505 44729 6 +26194 13014 11 +46198 57174 14 +35276 41797 11 +9711 21575 8 +57776 19818 9 +59758 56220 13 +4807 3093 9 +33671 11235 11 +29823 35039 3 +56523 48644 13 +53494 58352 8 +43491 54641 13 +32744 35769 6 +12697 49738 12 +34481 33107 10 +27650 45131 9 +51067 14299 8 +5633 29600 12 +26634 10571 8 +45590 33953 7 +55938 5979 18 +21731 30496 4 +41196 33498 10 +15069 30373 5 +46480 59193 8 +54021 59087 13 +787 53144 4 +8456 27412 6 +40456 10579 0 +7739 28071 12 +22919 33326 9 +28966 54950 14 +15246 28333 9 +4102 31085 11 +19006 16879 6 +45247 40290 14 +16628 44999 14 +13726 28310 4 +27387 16361 11 +28468 7991 10 +38050 38656 11 +29614 16855 1 +38322 19661 12 +58795 14446 6 +18197 29565 14 +43786 18685 17 +32702 17653 7 +14403 35457 9 +5347 2490 11 +29985 54986 8 +58280 1563 7 +52890 674 10 +18189 31938 13 +32834 24247 1 +2645 29964 8 +41963 59149 7 +4410 12206 11 +24940 28034 4 +49149 6168 5 +47083 35591 10 +945 13918 4 +27410 42582 8 +9203 7704 10 +3368 29025 9 +41154 39109 16 +19205 39384 6 +54639 13220 11 +2766 1338 14 +54150 2189 8 +23808 20626 8 +55607 59107 11 +53849 20024 9 +32513 41729 4 +48340 17787 9 +25492 13886 7 +56478 19517 10 +51019 18846 4 +54295 11791 8 +48230 18633 7 +18033 50964 9 +57442 51359 4 +27242 51669 1 +5851 18455 11 +51884 56079 4 +58385 51297 18 +55336 56480 12 +17648 35425 4 +56712 43988 7 +47097 31253 6 +35716 50750 4 +19851 35707 11 +26746 40989 1 +18792 29925 1 +27402 51015 7 +30423 10607 7 +13549 54030 16 +26520 19246 11 +1851 57652 14 +49633 59243 15 +39293 10105 18 +47614 18959 11 +36135 42098 8 +27114 58655 5 +55957 51797 9 +41928 13235 16 +51216 41294 4 +49441 58948 6 +38531 17046 6 +12678 59720 9 +17211 12024 12 +57949 20095 7 +32506 52880 11 +37275 38208 7 +14900 25558 5 +44962 14353 10 +7066 12249 5 +20090 41455 11 +53015 37444 13 +35794 16322 11 +33271 21195 13 +23241 57118 11 +38204 36153 14 +50430 53550 14 +22365 46568 12 +588 20201 5 +8720 30841 13 +41540 29466 4 +20337 14021 5 +55116 19428 12 +55994 5799 9 +8556 45583 14 +53301 26191 1 +43810 1401 18 +9395 9093 12 +16343 13752 16 +58211 37499 5 +29147 29884 10 +10252 58910 6 +15166 1261 10 +36238 28222 13 +17330 12364 10 +39400 37493 13 +41751 18319 8 +57658 58519 11 +21499 48224 13 +19974 9235 7 +50089 1020 10 +3116 2868 12 +8806 41957 6 +21401 25371 10 +54263 2316 1 +10822 33663 6 +23272 12489 10 +34186 43338 8 +30798 40704 12 +3089 14453 12 +6548 39804 9 +51959 22035 8 +11973 53522 2 +55419 15757 11 +40625 740 14 +23804 42541 14 +54741 25474 9 +38007 17367 2 +773 32735 15 +33198 59397 17 +768 10392 12 +57235 19117 7 +54004 18789 5 +10785 1369 3 +26077 47136 14 +46752 14817 7 +34872 53463 14 +12679 2560 6 +10710 29234 17 +48602 56452 4 +43008 54402 11 +35188 58556 17 +24765 7456 11 +3723 43674 3 +22597 6931 10 +52132 16351 4 +49404 22869 9 +18385 26275 13 +35723 25473 4 +38284 43742 10 +55559 2976 4 +14564 14539 4 +35107 42564 9 +50540 56897 12 +7936 2021 12 +45133 3607 4 +26713 42845 9 +32385 8608 12 +12116 54212 14 +38883 38935 7 +29894 42822 7 +10379 36172 17 +23095 55975 6 +52894 9784 11 +18473 36568 6 +898 11673 13 +51911 20866 14 +3280 4482 12 +30583 52776 14 +34575 8402 9 +19287 17379 4 +4828 22888 7 +24478 55361 9 +21602 47866 5 +10599 29720 2 +6530 8660 2 +52108 5937 14 +52888 35394 6 +49216 34534 14 +32643 17860 16 +44649 2113 12 +1181 35138 3 +5197 46348 15 +9337 14052 4 +8567 54572 10 +56557 20971 15 +46076 5681 8 +54539 7439 14 +18441 17913 13 +3661 38721 6 +22967 36469 10 +46323 38089 9 +19367 25519 10 +40426 25911 7 +38944 49133 11 +5300 29179 15 +11018 59058 11 +29175 8854 6 +2660 7178 7 +16535 1133 10 +4140 31750 5 +7315 31331 8 +10773 32902 5 +3696 17912 11 +6342 42330 7 +57880 16651 10 +7419 32823 6 +10881 52280 16 +58134 29798 13 +53421 43368 9 +10472 9859 7 +26350 51376 4 +42210 164 7 +7497 53642 8 +24178 34723 10 +47898 557 10 +57063 55053 11 +32258 56968 5 +12451 54276 7 +38086 17784 11 +20103 21182 12 +5317 33254 0 +38832 20705 11 +18004 41073 4 +22611 11292 3 +7678 8576 10 +25021 45581 13 +41787 33798 16 +34385 25660 6 +53896 42840 4 +42298 11509 10 +26813 1247 16 +5556 24544 13 +38225 24242 7 +16453 14455 10 +16335 48284 6 +20588 9487 8 +4488 10956 6 +36392 43094 18 +35173 14244 5 +47029 38984 8 +32109 8933 8 +53761 34435 8 +53625 28525 8 +17121 59729 16 +34672 7314 10 +58034 49311 9 +38541 14974 18 +15619 16844 5 +31082 30922 9 +17163 36818 14 +44929 1474 11 +38387 23205 16 +42451 47773 8 +29593 2185 8 +49330 59259 11 +26824 49696 12 +53025 8568 7 +6177 18400 6 +36953 25207 8 +18523 42442 16 +34683 46772 4 +58451 36271 2 +49027 38348 6 +59823 22914 6 +19732 47036 2 +8016 33655 3 +17084 56772 9 +49165 12221 9 +53835 54689 2 +30648 25689 9 +18531 31176 16 +5601 44207 2 +56732 3187 11 +11078 48628 12 +59188 35881 5 +43078 28003 12 +18353 59156 9 +56883 15482 12 +8690 51105 16 +25901 10617 12 +4986 1862 5 +3209 42769 8 +14512 30752 7 +9591 4417 12 +23535 22371 14 +1287 12503 4 +55708 32486 6 +12171 47764 13 +17924 37763 10 +15358 17742 10 +28119 40015 4 +55484 35673 4 +38576 1280 10 +46789 17477 9 +28783 21818 8 +13337 33665 7 +3720 1940 9 +46122 26170 4 +55102 39906 9 +18038 47213 3 +1698 54781 8 +55217 25498 4 +10569 26032 9 +57177 5781 15 +5965 37197 5 +56428 27618 10 +58151 19676 9 +30546 53392 15 +35218 49370 9 +45700 45461 18 +20483 50619 6 +35503 57101 10 +48136 27016 9 +28865 27706 12 +48133 25768 9 +46265 49927 8 +15110 15739 13 +47207 5137 12 +13648 23873 4 +56011 49011 4 +11981 38881 10 +35329 9838 10 +50421 1592 13 +58786 3995 9 +7154 15287 11 +17774 50997 13 +48671 54586 14 +45645 55501 7 +274 38842 14 +54568 39698 5 +41814 55254 6 +1263 7004 5 +57121 30526 14 +23455 16092 10 +30941 7914 11 +30494 196 15 +43981 5705 9 +26151 38811 10 +10648 18386 9 +1581 23690 8 +52422 12930 3 +33773 890 8 +6595 8288 3 +23817 57640 16 +22694 51281 13 +6746 20852 9 +37835 49485 14 +46721 43941 9 +48688 7519 16 +26114 26297 10 +16010 1764 9 +38504 40301 10 +6224 51177 12 +59592 56659 11 +12889 29401 11 +12245 16874 7 +39353 30779 10 +23433 27121 15 +27310 24324 10 +2246 10001 15 +57593 36482 10 +2838 38932 7 +4065 19835 17 +29934 33649 3 +23856 3934 2 +57458 51581 16 +37760 181 5 +15133 32222 6 +20649 46791 11 +59342 3165 2 +43131 44191 4 +7262 18352 3 +35254 27104 5 +53100 45444 6 +13615 43216 3 +49594 34233 7 +49543 58350 8 +34750 24764 10 +34689 58054 16 +33596 50242 7 +9460 51305 7 +22891 8598 9 +22908 40747 8 +24943 46158 4 +28818 1920 2 +1316 1661 12 +45413 30995 14 +44098 28936 5 +24683 44542 6 +18154 18046 13 +41986 17268 5 +35331 16495 3 +35913 24686 12 +2863 53375 7 +7536 6194 7 +3991 48949 10 +43172 32572 8 +38183 34962 18 +8300 12932 9 +54158 44320 12 +38895 23373 9 +51551 50624 10 +1076 48361 1 +12506 6550 10 +5842 53291 8 +26526 43421 12 +6909 57066 13 +19704 49120 14 +50104 37366 10 +50051 54627 10 +42214 19322 18 +41206 50144 13 +59900 50281 4 +42826 48899 11 +21917 28782 10 +52154 6936 5 +11764 25501 13 +1377 39291 8 +2950 30549 14 +50381 14800 4 +2729 37256 6 +48422 21468 10 +54221 51340 2 +17892 22850 3 +28737 59161 15 +4105 41774 5 +52875 17145 13 +59339 22709 7 +296 50954 5 +43443 31232 6 +4281 34484 5 +52045 2328 5 +55061 22019 10 +24084 45395 10 +27554 58949 13 +3950 4926 6 +3890 53964 11 +46414 26805 10 +16095 9778 8 +45064 4362 13 +27164 52561 14 +25895 52191 10 +28298 44205 7 +47186 8743 2 +3185 45718 9 +53455 23651 7 +47026 56414 15 +42951 31401 5 +12769 50039 13 +26241 24576 6 +41091 41304 13 +25470 35346 7 +11128 46992 6 +42770 11679 5 +16745 4325 5 +57429 19096 8 +4852 57223 1 +44141 39059 9 +8249 44791 4 +25432 28061 16 +22200 31775 5 +26844 11104 12 +58789 8067 9 +24720 58334 16 +50212 50720 5 +3872 33292 8 +39773 47465 6 +4401 54933 8 +54974 54483 6 +1685 10730 7 +38016 12270 7 +32497 12898 12 +796 58859 17 +21640 55680 0 +44361 53606 15 +35431 47989 8 +11894 13798 7 +29759 19522 9 +16518 52225 2 +52996 6686 11 +30975 31766 3 +2156 8326 12 +28903 10625 8 +12951 24688 3 +2208 36040 4 +35672 25942 9 +31692 43217 8 +19243 29402 9 +10790 8112 7 +4165 17322 2 +39489 10986 10 +10722 34918 15 +17569 39443 7 +57449 50217 18 +54389 12810 15 +34390 6033 6 +48572 18608 11 +55615 21439 11 +35389 53548 8 +18711 51292 15 +44359 36424 6 +9310 9195 0 +49274 10340 4 +9334 3336 11 +1845 31045 5 +39381 11237 10 +5378 41255 7 +12066 59370 15 +24807 11153 4 +18686 11327 10 +38435 40169 6 +17458 55514 7 +41290 14279 10 +3489 33712 17 +18 35234 10 +26137 20288 10 +12013 1890 7 +9789 30069 17 +52796 35786 11 +19788 38107 8 +22734 28588 9 +51813 47569 5 +26281 41374 4 +27713 4195 8 +11891 40326 14 +35753 32521 8 +32599 37796 10 +25391 52926 12 +25310 42664 1 +50558 52850 10 +33454 57588 8 +4115 1761 6 +9177 24130 14 +38677 46181 2 +5143 26541 5 +30996 28937 3 +15778 38885 11 +17741 17619 6 +31174 11928 6 +35424 30457 7 +37279 55135 13 +30003 19335 12 +7547 23937 13 +12104 42504 14 +30041 43215 11 +6984 52988 9 +28722 18505 9 +43801 45780 6 +44935 19387 10 +29950 19848 12 +39277 30654 16 +8970 25612 5 +21219 20414 4 +53690 13777 5 +15241 938 3 +25385 4344 9 +22932 54023 1 +6906 23500 9 +46931 14972 4 +54844 18905 4 +57477 16259 4 +14909 1357 9 +14087 46742 12 +13652 33580 10 +52754 29287 8 +48800 23629 10 +55009 19346 10 +38269 34973 10 +8865 57168 8 +28602 1583 9 +52231 47711 7 +36349 1645 9 +44058 26009 4 +6115 1497 8 +45893 19782 2 +22775 30157 12 +33895 44014 13 +54345 45881 12 +50192 24457 8 +41309 37343 8 +14538 30518 10 +54961 15590 9 +48467 55562 11 +5592 5918 18 +25163 45622 7 +6735 11752 8 +45685 48096 11 +17407 18394 10 +18190 14609 9 +10606 6592 6 +22572 990 8 +31065 16221 3 +18946 59661 9 +45396 58108 3 +49938 42366 5 +5892 37102 10 +50575 45967 9 +53332 13755 10 +54022 52004 13 +30631 45900 9 +5471 25225 6 +31362 10994 10 +17189 7402 4 +50251 25483 7 +45744 21120 15 +37338 21227 14 +56979 38907 10 +23949 56675 12 +20050 23584 11 +41441 41008 17 +52183 29355 8 +21971 13557 9 +58857 55775 7 +33674 22311 9 +38821 36593 6 +15458 49235 15 +42389 29880 5 +55357 32435 10 +12643 52109 3 +35074 44434 7 +55252 1106 13 +2875 23312 7 +47763 18908 10 +32511 25694 5 +21804 37863 4 +23765 20665 10 +48672 970 12 +23412 7930 3 +31377 2787 10 +17808 9698 8 +49644 52902 12 +6970 4456 9 +9761 2041 13 +52026 21087 14 +42476 53976 12 +22986 50723 6 +35930 46921 4 +57175 51683 16 +15466 25330 7 +57685 22543 8 +31575 46967 6 +36769 10081 8 +35945 56379 5 +17032 56729 8 +11906 36528 14 +58067 49716 3 +39951 56205 17 +37434 21821 14 +58883 24001 11 +41589 7707 9 +35499 21266 7 +24269 25398 5 +46454 53435 12 +37465 48563 8 +57299 36596 13 +58355 31650 6 +31140 1340 8 +11925 51071 13 +2969 41775 11 +6903 30932 6 +32119 13775 10 +36407 2470 11 +3038 50691 6 +5469 49681 1 +27972 4570 11 +49161 48022 7 +4040 11053 11 +5702 33605 8 +9765 4085 15 +55351 30439 4 +11598 27867 11 +1417 12692 12 +42061 23908 8 +59703 291 10 +32597 2595 10 +25835 6974 10 +53228 40946 10 +975 33777 11 +17009 3487 1 +44585 13500 6 +31812 42208 15 +58439 23007 10 +47589 18277 13 +21896 25739 12 +26792 881 12 +34066 15229 16 +32299 3835 6 +23687 33286 15 +22651 50015 15 +39664 36913 8 +23219 36685 3 +39553 43169 3 +29455 58374 14 +28575 54941 7 +9530 25616 4 +31204 53682 15 +39158 18990 9 +37051 42988 16 +14425 5614 9 +28951 5020 6 +358 46037 5 +21847 55433 3 +15781 30160 5 +55261 19857 5 +4660 37522 14 +18922 542 2 +395 41606 6 +7329 40182 13 +31987 27245 10 +26585 43672 5 +22849 31701 9 +22408 846 9 +25486 54764 8 +45862 14838 5 +51663 27439 8 +3684 27090 9 +29774 7492 15 +9068 21570 9 +50364 35152 7 +49991 14039 5 +2417 20030 14 +37859 45747 9 +53597 40186 16 +12761 38758 10 +2778 56749 14 +9381 47142 7 +48246 34369 2 +50636 53772 6 +38612 5946 12 +56474 35689 5 +39150 41929 10 +664 38101 8 +41219 12950 11 +11037 28728 9 +41102 9972 11 +58015 43014 3 +58693 15962 9 +13996 39184 12 +12307 57319 5 +25965 9171 14 +56854 10663 14 +45226 23954 6 +37311 40347 9 +4197 57643 11 +34219 26496 11 +35604 42463 9 +27348 28405 9 +18226 6699 10 +8984 2319 8 +23597 20882 7 +32644 22084 9 +24399 43279 7 +21547 18586 7 +54605 27033 3 +16152 54035 16 +54088 29741 5 +40065 19619 18 +32647 8210 12 +25564 25512 2 +44705 37745 4 +11923 49923 15 +34793 30741 9 +52538 29714 16 +34642 1190 9 +30176 43576 3 +7017 9882 14 +7077 31088 13 +30499 37237 6 +3006 50553 9 +30497 24946 18 +51219 46802 15 +12155 47941 13 +41099 22360 13 +59194 42385 18 +446 48625 8 +13033 32432 7 +10627 21542 1 +15532 45045 15 +30733 36089 8 +11254 19859 7 +46026 4486 2 +56857 29636 3 +54151 20535 13 +55506 7691 5 +48236 50134 5 +57985 31580 8 +43632 10157 3 +56440 26514 5 +4411 11318 5 +24819 50597 13 +30994 12141 9 +11712 52600 4 +57872 26815 12 +34164 55143 7 +30985 648 9 +18440 21410 11 +51108 27452 5 +4005 1050 6 +10586 8807 11 +19324 50688 5 +49118 37600 9 +45566 35957 13 +44356 34916 11 +20565 23198 9 +6619 16694 1 +42230 46393 6 +58366 2124 17 +20904 9341 14 +9526 9431 10 +39525 44383 9 +37929 5710 8 +57918 1957 14 +1045 42335 14 +26964 57654 9 +31612 46554 11 +20662 50745 8 +30061 51125 9 +30326 59336 4 +52847 55789 2 +16729 42831 9 +45378 2062 8 +48164 4274 7 +53373 21634 3 +21991 52585 4 +30275 19269 9 +39660 7607 17 +22802 4786 10 +46485 55435 12 +13717 17963 16 +19780 53386 16 +41791 11263 15 +28582 57881 15 +3407 6471 13 +8424 43858 13 +14977 18224 11 +19399 19430 5 +13724 22994 7 +31026 29380 6 +10789 35578 10 +3211 38201 12 +23951 18153 16 +36972 7905 7 +22875 49743 15 +19939 24061 11 +41293 45892 13 +20106 37596 15 +7343 21106 12 +2032 20358 13 +26215 59348 16 +57718 44655 13 +7601 20064 3 +25121 3510 16 +36670 57922 17 +4716 24628 3 +41205 34168 2 +26861 57017 16 +2842 25794 9 +59889 5081 10 +6783 32389 9 +1458 22079 9 +22374 28571 6 +55171 57233 13 +23070 4205 11 +37357 12699 15 +38121 2982 16 +23811 2133 14 +49818 25263 16 +1003 27820 1 +40806 10493 7 +29450 2195 7 +95 15396 1 +52540 56214 10 +29607 35514 8 +771 26997 14 +48499 32345 9 +12541 11070 14 +10152 30630 7 +35749 47255 3 +28609 25357 6 +34845 6872 12 +54261 48222 18 +39471 37122 12 +26242 41204 6 +49511 24532 12 +20098 31184 13 +51701 50614 10 +58203 9572 3 +34430 8214 11 +2639 37092 5 +38436 25980 1 +59332 33764 16 +13806 10345 10 +26591 53989 9 +48111 40686 2 +58868 45973 9 +14587 12696 13 +4012 5588 4 +57942 51303 5 +25472 35489 11 +20285 20923 11 +1226 11402 8 +46258 41430 14 +32726 37129 10 +43571 584 6 +9045 25256 9 +12112 47784 9 +4806 23195 13 +31014 56664 10 +43943 56974 6 +59516 52316 9 +14421 35000 7 +15461 35725 6 +38068 8025 4 +36336 46197 6 +45209 5665 6 +37498 51979 13 +34123 53594 10 +57068 53743 8 +9925 6696 15 +23249 37634 9 +7833 1972 7 +49884 14499 9 +24982 24538 11 +46108 12637 10 +20613 18066 9 +54634 35517 10 +57815 49693 8 +23346 12172 15 +31884 18771 8 +29547 17169 9 +56010 7521 4 +5726 42127 17 +41654 12395 13 +52702 18442 4 +14263 2742 12 +45062 14320 12 +32011 31171 8 +31037 210 6 +51601 43663 17 +42825 32010 6 +12061 26886 16 +5760 16063 6 +23181 4837 5 +48715 41447 0 +12123 8528 10 +46015 48660 5 +2295 16317 12 +10328 37162 12 +13563 5357 11 +41613 46927 17 +19684 35638 8 +59476 42190 8 +3308 2489 5 +53133 31666 10 +44814 43494 9 +57859 6497 5 +58660 6496 3 +40844 12175 9 +38587 58030 10 +58055 38724 7 +9085 51700 7 +52402 47399 11 +2057 51993 14 +35796 26236 8 +24736 38244 16 +17970 20159 13 +44498 25746 9 +57830 29991 4 +35748 40788 6 +22252 15432 6 +43417 44278 3 +17743 51648 10 +43768 56240 8 +17726 55565 6 +48315 6988 12 +12846 46977 11 +13508 58607 10 +21095 16146 9 +23823 16543 0 +15636 53969 14 +42842 55193 4 +9531 14372 11 +38802 25716 7 +18506 13593 15 +2727 15963 13 +48180 26160 6 +23549 48575 11 +8646 30394 14 +24967 38360 14 +17430 41252 1 +692 27946 7 +6661 50841 13 +37144 18927 6 +58275 39148 9 +10643 47677 11 +34878 36455 13 +307 24313 16 +52 799 12 +37784 4229 16 +45558 13733 7 +47483 43987 8 +47138 2682 13 +50800 55630 9 +29909 6425 3 +39948 37987 15 +815 35363 9 +12937 15309 14 +38808 9820 0 +38024 25597 9 +20404 2897 7 +25629 7968 6 +13219 25067 9 +28175 54160 7 +38268 38869 9 +29679 23258 7 +10921 43762 6 +40657 59047 8 +7079 52626 8 +17271 25495 11 +26070 18468 2 +10623 26726 10 +16308 19022 6 +58222 30519 17 +49666 36630 11 +26773 53795 13 +33700 44685 9 +19079 50620 15 +34362 30279 11 +10421 547 11 +2142 28060 12 +31950 56046 2 +53604 1150 4 +23913 17745 7 +55707 12824 2 +18624 34830 13 +14593 11578 10 +31530 27963 13 +29569 50590 11 +30030 35879 9 +50568 47531 4 +52248 31958 3 +51882 20471 1 +28679 43179 12 +28792 49881 5 +33971 40104 7 +40984 31872 13 +42036 16602 16 +40988 11188 9 +27030 52407 15 +43210 28932 11 +52562 23528 5 +7832 39762 12 +6849 9768 12 +20518 29843 15 +47395 53767 7 +3025 12369 13 +26146 18337 2 +40519 8369 4 +16705 30001 7 +16624 25108 14 +5906 25624 16 +14431 55502 4 +52363 39952 12 +31495 28185 7 +22287 22334 16 +28273 10082 9 +12628 40249 7 +50583 252 6 +75 53768 4 +22309 1634 11 +11458 48402 6 +6236 23347 14 +8642 31610 8 +5318 22303 3 +24036 3870 7 +43694 1528 7 +9186 49430 4 +39217 47623 3 +40824 41101 5 +27011 3066 9 +31323 38179 1 +17459 46401 5 +16100 9802 13 +3306 20927 7 +52413 763 11 +46537 34252 11 +25774 19180 1 +59457 10611 8 +36208 12513 12 +34655 28756 7 +47586 59735 8 +5573 56819 5 +40551 51433 6 +57463 13675 9 +25286 13715 13 +45947 44743 5 +54878 52786 11 +35248 28688 10 +2577 26788 10 +35963 14689 5 +4866 23311 12 +56992 32523 9 +1818 32550 4 +41298 54714 6 +54217 33404 13 +40951 37662 7 +48869 11515 16 +33576 22680 14 +53431 32461 7 +47437 22180 11 +22332 49143 18 +38635 29029 7 +8908 30229 9 +4353 36677 15 +55966 30459 5 +16064 31508 8 +53781 35306 14 +32564 41619 3 +49335 1038 18 +14017 27658 8 +18466 27743 12 +39115 32465 1 +429 52130 0 +41692 55759 14 +39713 23964 17 +6885 35844 7 +50802 24710 3 +26120 11439 3 +4836 8771 6 +54661 9984 10 +28274 49250 8 +21745 40664 7 +57366 610 7 +1677 23526 10 +15116 39526 10 +29729 11403 8 +1136 45087 7 +57386 39732 16 +25652 19144 18 +35659 50535 8 +17634 15843 9 +31148 29829 10 +48309 51153 11 +5547 44306 4 +50694 37800 8 +23894 57585 6 +50536 44321 15 +45935 36433 7 +32246 29489 7 +52934 2849 6 +21733 25269 9 +34688 4061 16 +25653 3758 5 +11707 22962 11 +32238 48027 5 +23936 47855 4 +23744 18009 18 +44978 11420 4 +13770 50081 6 +44939 51659 10 +13479 48135 14 +12396 3987 13 +56878 48583 7 +37236 16622 15 +42737 6979 8 +32281 30646 12 +27331 28410 7 +26223 27162 11 +28145 12269 12 +20581 42670 9 +5609 16756 15 +2480 51009 14 +37527 6290 13 +19015 4765 9 +2833 27540 11 +46871 40763 3 +16851 20584 4 +3274 47886 10 +46228 26095 3 +22310 52654 6 +42689 50650 11 +20200 57844 9 +44630 8415 7 +2404 49734 9 +52593 45543 2 +17583 13338 6 +47198 47190 4 +7474 20248 18 +17368 12815 9 +35525 36629 9 +20623 14637 13 +34652 3255 13 +53284 55955 3 +30320 5083 0 +7452 9348 10 +11914 22913 8 +33325 13333 15 +46741 24115 10 +36284 56627 16 +18805 54732 10 +10391 29361 9 +42518 18799 1 +7073 14200 8 +49718 5721 12 +41733 42744 1 +33524 17412 11 +57711 15010 4 +33270 57166 11 +22110 11879 13 +20940 8148 14 +39880 21907 7 +38302 13213 7 +21989 26473 6 +21841 18120 10 +55067 32841 7 +19392 46563 11 +17076 22966 12 +17486 43141 13 +17747 14255 8 +28708 12698 9 +40943 50264 10 +16440 22824 17 +58635 40452 10 +53776 48121 4 +10474 55766 15 +53700 49986 16 +13945 14285 13 +9665 28749 15 +34519 38961 6 +7552 23829 3 +24971 11955 6 +42609 7119 6 +30891 51811 3 +34158 2959 3 +17865 45048 8 +47272 47874 10 +30915 18855 10 +16635 22598 12 +53465 23864 16 +1422 30335 8 +4170 58082 7 +57717 40503 11 +54232 22220 7 +24266 22843 10 +28615 6742 10 +40821 10224 6 +3678 40855 18 +15620 2700 8 +52573 8698 15 +21612 15971 0 +30091 10155 5 +19539 7860 10 +26794 44193 5 +27269 49655 13 +13564 43354 11 +24979 22187 10 +47533 22839 7 +2657 25194 10 +38188 16290 8 +54012 6920 3 +14833 28282 9 +8443 54602 8 +9290 58956 13 +28956 1495 7 +56268 34039 9 +29479 26320 6 +54390 47570 13 +56275 10948 11 +53446 37415 4 +52313 41509 5 +5675 53434 3 +26310 1384 9 +9118 7424 10 +47253 37463 8 +47402 41987 7 +521 54265 13 +55355 8809 0 +11954 37169 4 +41182 56147 6 +28813 52072 16 +26036 20284 10 +41381 4839 8 +32549 58231 10 +19297 8169 4 +17300 20884 5 +11687 48074 8 +58770 5931 12 +51874 996 11 +15070 58483 8 +8677 6708 4 +16314 52617 4 +8562 47175 11 +21105 44055 13 +52462 8329 18 +3348 24567 10 +47787 36242 5 +22260 27034 7 +28236 40617 9 +14229 24541 0 +34054 34676 7 +33560 19168 7 +20727 25699 9 +42830 50282 6 +43398 34476 13 +49800 28988 7 +42307 56448 4 +30071 26307 3 +24114 45698 6 +16413 27002 14 +42517 22279 12 +55592 1074 5 +23630 36755 8 +22998 45976 10 +56431 26992 13 +16363 40731 5 +25276 28353 14 +25450 41512 3 +37560 43043 5 +45448 7901 12 +21628 6960 0 +18646 47881 6 +57965 36775 6 +33063 22695 9 +42806 37492 5 +52611 3210 9 +29538 9250 12 +47482 22387 6 +37315 27705 15 +20209 27015 14 +54870 43007 9 +28355 22842 10 +1433 36870 13 +52590 48099 4 +33398 7078 2 +36810 52581 12 +15393 21807 16 +20936 49126 8 +26795 21636 11 +20952 2894 4 +11623 54407 15 +50009 51248 13 +1134 70 3 +54401 43820 10 +50293 42725 8 +15699 38571 8 +23374 54455 13 +14658 12688 11 +29256 12139 11 +10461 22613 14 +35225 15680 9 +10096 53904 8 +44048 11114 12 +20037 44194 15 +17297 47233 10 +39999 54763 14 +57285 8348 8 +55776 17512 12 +21685 53556 11 +41114 46837 9 +37096 39930 10 +20154 37539 14 +6893 6637 11 +13440 15473 9 +40227 53805 6 +163 36690 9 +8724 16517 8 +43149 40218 0 +49623 32878 10 +24932 18053 2 +53829 13477 13 +10441 18718 5 +51840 33358 18 +38169 35614 10 +16242 35140 11 +17429 41598 9 +55443 22021 4 +44153 45640 10 +50971 10188 2 +5506 59021 14 +53687 28597 10 +37958 39849 5 +19385 55904 12 +14994 49080 8 +46966 43077 4 +54879 1501 3 +45932 50773 4 +21710 43225 13 +52309 35991 10 +23228 2092 9 +15301 1574 14 +29618 8581 17 +35062 12174 13 +6664 35949 8 +55878 53844 10 +15314 8613 8 +49572 46307 13 +28674 57921 16 +41754 52777 6 +40655 28982 10 +18433 21665 10 +44696 14209 8 +46253 9615 8 +38199 38888 8 +23083 5264 11 +5753 9959 6 +39171 24109 6 +40306 7377 13 +36192 29413 10 +3285 40695 10 +35688 54346 11 +51038 47484 11 +40931 16992 12 +54921 48834 4 +9110 33670 1 +3283 18926 7 +28123 13265 12 +29142 46139 8 +10748 49271 10 +33825 21932 5 +20421 41181 11 +16167 1293 7 +53410 17036 13 +18559 29292 17 +9539 25280 14 +40934 19118 10 +47071 6087 14 +55466 56707 7 +9657 22033 12 +4846 17351 3 +56876 27683 9 +5872 15561 6 +29384 38285 10 +45167 38154 10 +44781 21335 12 +4215 32212 10 +6752 25969 16 +5013 19682 2 +26227 29421 6 +1227 25106 7 +37098 4967 15 +30670 16824 15 +32701 45980 15 +14706 18595 16 +1644 2245 3 +54710 7978 4 +26966 53861 7 +28657 22291 11 +29540 51543 3 +42529 52785 12 +57240 47982 6 +4408 51338 10 +34311 12514 10 +21265 48366 13 +35046 13788 6 +33447 38057 8 +32125 51913 13 +22116 27117 14 +59718 10250 16 +37820 35042 13 +47728 34921 16 +15159 21285 9 +17122 59628 2 +49505 54408 8 +37089 8641 14 +17762 6169 12 +11349 17048 7 +27763 3177 4 +1371 11721 5 +6076 23291 1 +13162 56160 14 +579 33343 6 +44887 17500 3 +12526 27433 11 +44609 16649 6 +25535 25364 4 +57687 3391 4 +36988 30888 13 +20657 20771 16 +8013 57532 11 +47316 19112 4 +31732 52424 12 +47169 52208 3 +55384 19199 14 +1707 27088 10 +45666 4903 2 +29875 51696 9 +16521 54231 17 +43569 3086 14 +26998 34050 8 +20734 11680 15 +14561 43037 10 +42666 31290 6 +33468 54673 8 +20697 41170 9 +35784 14057 14 +6515 41560 10 +44731 20755 5 +58071 28302 8 +29008 21947 8 +51954 2721 10 +27596 21985 8 +23451 13550 9 +28292 40991 7 +58314 27300 3 +17313 8394 5 +25309 28364 10 +26614 6233 9 +11804 21682 4 +42004 43073 11 +50908 44784 11 +2703 9733 9 +42007 32881 9 +52194 14880 9 +35007 30851 12 +36727 36921 9 +51137 57552 6 +27680 23124 2 +12057 55422 7 +45397 38967 15 +43259 41470 16 +36261 17610 14 +33634 7484 3 +28309 14226 15 +54089 11912 9 +21546 34928 2 +3486 59690 6 +47473 50481 3 +38632 27218 13 +21525 47347 7 +19838 50198 15 +1759 34931 11 +22675 19980 8 +11005 6267 10 +40114 11601 9 +37243 47099 10 +57225 33707 4 +53128 48700 11 +54210 45582 6 +33462 20556 2 +59814 59757 11 +58357 52260 9 +8691 52857 7 +12773 14139 11 +24944 25520 12 +41956 19238 4 +7894 16345 1 +50154 29478 4 +18764 38275 4 +37619 41075 4 +35265 35928 16 +26334 27169 10 +19554 39018 1 +29182 21172 12 +57983 28723 10 +4637 58406 11 +10745 3079 10 +12819 10324 14 +50174 23586 9 +17370 57565 13 +136 12912 7 +52789 59006 13 +4793 21504 2 +17151 34813 9 +53154 54770 13 +50406 15972 14 +35453 17052 4 +16761 49905 5 +51020 56491 10 +58184 40420 6 +31134 19120 10 +42149 33333 11 +1673 29921 15 +9237 44701 15 +33617 37171 9 +38178 27373 14 +19523 10874 6 +3178 7161 5 +58645 30680 6 +15663 47084 6 +28844 37007 4 +13907 37871 14 +31811 19489 11 +34060 43182 14 +13443 27089 4 +29620 37886 9 +51594 26209 4 +43481 36087 9 +1344 47377 11 +32199 1784 14 +58376 7579 4 +39896 53836 8 +32205 28617 11 +35692 28913 6 +15995 43197 7 +41213 8085 15 +46232 11186 13 +17409 8355 3 +12559 19365 10 +11287 10590 8 +7140 762 8 +58749 25735 6 +59099 2997 9 +25613 18493 5 +43554 32363 7 +1322 53178 8 +49435 46045 9 +13938 58763 6 +59660 53705 3 +41317 29543 9 +7286 32028 7 +35709 3080 7 +21928 7982 4 +35463 45630 6 +51938 48448 13 +51430 15936 12 +22477 14224 4 +25057 48904 4 +49756 58505 13 +40294 57591 7 +34701 51436 4 +32257 36130 9 +50979 59357 5 +37488 45625 17 +15891 27757 10 +2762 28665 10 +11270 7309 12 +52000 38936 12 +13346 50321 13 +27347 32710 3 +2204 25930 9 +15357 47818 12 +36660 7117 14 +792 43874 10 +940 16446 14 +29744 25894 8 +2174 12561 8 +51024 6441 0 +34558 15202 9 +3195 14136 6 +53014 19377 3 +39056 53215 13 +41624 16846 12 +23762 738 2 +27353 15878 6 +10602 21183 9 +2376 20013 13 +18852 5804 7 +20036 51645 9 +32696 10375 12 +29246 23069 5 +27178 16093 6 +58411 33057 10 +57310 56358 7 +55818 795 12 +39322 39288 9 +16143 31817 11 +35519 26193 11 +14631 46776 9 +20713 33088 2 +32525 23380 2 +3659 32651 9 +15119 6117 0 +35336 12285 7 +31689 42675 3 +23010 6843 14 +43388 44837 11 +48717 45707 10 +8729 9949 12 +40960 14558 11 +42183 58569 5 +34276 33260 10 +21024 48548 11 +6666 32323 12 +48151 3476 15 +14309 59549 7 +46472 38223 7 +14311 43751 9 +3377 52361 1 +45191 23637 12 +29813 56166 15 +33055 44646 10 +49156 15716 4 +28001 15428 7 +10841 33229 10 +49571 58606 14 +1797 25665 6 +55168 45221 7 +53396 30084 12 +56204 42014 5 +11819 13657 7 +33975 18912 7 +14268 28958 3 +58000 2669 5 +292 31023 12 +26564 27547 4 +59221 49759 14 +45782 26014 4 +33021 18296 18 +50923 15068 8 +5320 56209 16 +47296 30317 7 +19621 58495 7 +24439 13000 12 +33274 41358 2 +42221 29060 7 +628 45067 14 +12320 58398 11 +43961 1690 5 +24539 15982 5 +27363 46807 9 +15011 21480 8 +51846 16196 10 +22256 35106 11 +18794 23280 1 +11821 242 10 +8000 33114 3 +38405 47396 8 +40486 55077 6 +52608 9603 12 +39727 47900 8 +40848 18604 5 +16870 40860 9 +10920 475 3 +3620 4036 15 +43814 39523 16 +39908 24403 11 +44327 34893 4 +13912 49175 12 +875 42286 7 +15513 54010 7 +24037 7107 8 +7020 32833 7 +57720 53540 6 +3972 17023 11 +15548 15978 7 +13238 56794 7 +30761 55685 10 +21922 36671 7 +56737 1202 7 +49537 19268 11 +39878 18491 9 +14889 8389 13 +56801 31927 7 +46179 4487 10 +37624 33373 3 +6261 59374 10 +54894 19797 7 +51711 20083 7 +26573 55866 7 +27067 4654 4 +23612 1652 8 +6606 24498 16 +3737 41072 13 +16826 16592 13 +57098 10256 9 +23471 30469 15 +41768 54684 17 +10568 7724 7 +30510 27120 10 +12256 25429 12 +57731 20546 17 +1278 23858 10 +44170 13022 9 +51073 5706 4 +3763 37040 3 +4152 48256 9 +39080 22766 8 +1719 16978 14 +6269 5582 4 +24863 35479 10 +55511 18639 9 +14666 17888 7 +58104 31451 5 +37567 22038 10 +32278 22951 9 +30981 52913 17 +47500 13166 11 +1356 44989 11 +28012 4462 12 +39656 50455 7 +55244 7530 14 +26858 2746 4 +45716 5876 6 +58978 12207 10 +40815 19789 6 +27688 16454 16 +23460 41855 11 +18962 20309 9 +16856 3591 7 +55628 54988 8 +24425 36428 6 +19881 20858 14 +18173 14153 7 +19486 14125 3 +41209 32409 4 +57665 12094 11 +29508 43100 10 +41501 18073 9 +41415 47703 15 +12215 7321 6 +1543 17524 14 +43485 11776 11 +29198 11810 15 +35872 1301 4 +34858 37176 9 +50611 937 7 +11630 4512 4 +15783 47701 8 +30629 15946 9 +49669 9762 17 +43108 28332 12 +14055 16055 17 +3090 30829 10 +58246 57738 7 +57775 35002 10 +16425 24965 9 +41373 20396 8 +56908 865 8 +43357 50548 13 +38508 17047 7 +27776 19748 13 +50300 56994 6 +28445 48115 17 +13067 58200 9 +59247 51111 5 +1187 30351 9 +650 56107 9 +54564 19454 8 +26644 53381 3 +48088 39167 11 +28808 37826 13 +8030 284 14 +44496 54378 11 +7063 52841 8 +34101 23499 4 +43392 1511 13 +8039 8283 10 +1352 25560 14 +16841 14234 7 +51494 58600 6 +29801 40552 11 +12030 39837 7 +28607 14996 2 +22832 9294 3 +25123 3622 7 +10858 19907 8 +3399 54541 6 +33744 16670 10 +29258 21820 9 +23974 14970 9 +18358 1303 13 +46456 2502 11 +47634 38170 10 +4277 14010 18 +36410 20276 5 +45811 2350 10 +7320 30923 8 +11848 23324 5 +53694 28223 8 +4820 23269 9 +37292 43435 9 +51196 906 7 +19514 41299 7 +46057 42797 4 +5026 55785 6 +26235 27961 5 +5803 33154 15 +21225 34633 12 +46024 19350 14 +57462 50094 6 +29091 37008 10 +3530 5522 15 +26186 4158 15 +57842 27411 6 +54666 51810 11 +37837 15646 7 +34856 18138 11 +8485 44960 12 +20318 23764 9 +2708 5019 1 +29911 49090 4 +43334 21865 13 +38959 41134 11 +12978 17045 9 +10695 17654 12 +5016 6928 2 +24693 42699 8 +35739 54839 5 +30974 18859 12 +56982 37027 5 +57252 2338 4 +37902 13793 8 +1079 5593 10 +46549 54317 10 +20777 30455 5 +12429 7126 15 +44130 47457 9 +30935 2141 16 +30330 59666 16 +2275 5976 10 +1370 28800 13 +24089 11027 2 +45651 29788 5 +32654 49863 7 +14011 9835 16 +8185 17805 3 +15578 14688 6 +40786 17075 15 +45140 35867 6 +20968 25086 12 +12384 58765 4 +4295 2988 4 +52945 58872 9 +44246 39431 13 +29188 45681 6 +4755 27288 8 +52330 18467 15 +19026 14837 6 +20621 50871 16 +10099 7844 11 +56090 17673 12 +28097 29035 11 +3198 40075 0 +34388 43457 7 +12639 51609 13 +54291 26434 5 +32302 52113 13 +39892 2984 9 +39021 46450 13 +54847 12857 14 +44868 53723 16 +9906 27778 6 +32827 38570 4 +43592 51941 13 +32530 32856 3 +19027 1396 9 +44593 41612 4 +42682 22148 17 +47625 58152 12 +3546 56773 10 +58424 58235 10 +35845 53281 15 +53253 14338 15 +31806 14807 8 +25296 39613 12 +55294 56287 11 +53489 6540 3 +59775 28863 10 +2377 24517 4 +10755 12481 2 +27203 7127 7 +54592 3267 16 +50301 12196 7 +43247 22269 2 +33317 52715 5 +3319 57100 12 +47973 9970 10 +46814 58633 14 +3499 28193 11 +1416 4683 13 +27719 1746 9 +33224 49392 2 +26823 32423 5 +1355 22105 13 +39424 6241 12 +118 48152 6 +57953 27518 5 +27398 25505 10 +439 38503 12 +36888 40926 8 +4925 5203 7 +41354 30513 11 +22158 9204 1 +13004 30305 9 +17707 6631 15 +57758 54279 10 +21929 2542 10 +30340 17568 4 +11689 49253 12 +14009 922 11 +42240 15409 5 +32070 33331 4 +3481 47380 12 +52685 5816 8 +33448 21615 7 +14845 23857 9 +49104 52044 14 +14093 29488 8 +58273 21874 8 +59769 41404 6 +15395 52737 14 +30138 40881 11 +22541 56074 12 +43794 10469 2 +6528 51274 10 +15823 35165 5 +38316 27704 10 +49981 50922 6 +9091 18798 12 +27377 52582 7 +30477 23492 3 +33307 46872 15 +24713 8840 8 +2575 42520 12 +58779 14527 11 +18185 12504 4 +15767 1 5 +26525 24550 16 +5004 52738 2 +840 38055 3 +31639 6123 3 +11818 14150 9 +55058 50743 12 +26653 51185 13 +23709 49781 2 +26432 46436 5 +45530 18359 8 +10228 37477 8 +28259 31404 8 +16746 128 7 +50305 36863 16 +47149 15014 10 +22144 28085 6 +8468 2374 10 +40362 32810 1 +56027 12234 4 +39453 49333 11 +39979 59083 9 +51270 3863 11 +34913 4068 8 +36008 32787 12 +44993 11039 5 +18786 2146 12 +41808 30015 12 +2259 9282 10 +4058 56537 9 +14720 52646 13 +17792 38186 16 +10754 6998 7 +6286 17372 5 +35086 5312 10 +10808 16366 12 +6882 33801 15 +19795 14135 7 +59591 42512 15 +1444 9650 10 +27156 50058 12 +32122 32793 7 +55549 48289 12 +51199 51678 8 +1508 26987 12 +36193 49318 8 +26211 39802 14 +50924 55606 8 +22902 6234 18 +55804 40897 6 +59556 34656 2 +38569 29735 7 +55218 5639 12 +30490 15384 12 +39687 49727 9 +5462 39286 9 +3249 1434 15 +14961 43227 8 +54743 56184 13 +12038 44640 8 +2369 46255 17 +21797 29771 9 +11583 10698 9 +36156 9550 8 +27649 51684 7 +56279 14173 17 +48675 13809 13 +19488 50122 12 +44880 11652 12 +24893 56243 2 +43426 40092 9 +17476 17581 0 +35606 16306 2 +58595 13734 8 +20210 13986 9 +28361 57041 1 +29275 14198 10 +54632 24205 10 +19767 35853 2 +37 33669 0 +14384 41955 2 +53837 28183 11 +3137 44446 6 +40765 46011 5 +9771 50711 17 +53914 31186 9 +46592 1828 3 +50019 25749 6 +17878 16981 17 +34047 8526 13 +37971 17937 15 +7543 31044 9 +33818 11685 7 +39759 33389 2 +9102 6476 14 +27747 38528 8 +56573 35982 0 +38775 58096 18 +57621 44608 10 +52684 3595 7 +57877 13157 4 +43060 53841 17 +1615 34024 11 +36531 37963 14 +47150 17842 4 +59 25743 1 +59536 28721 6 +39446 38398 1 +52028 17280 3 +20597 26342 9 +50978 29864 11 +59542 37414 13 +24882 39832 15 +10410 45488 11 +15223 45443 7 +19643 25649 8 +31168 13314 8 +43545 10749 11 +28925 12303 4 +16712 38862 9 +52303 55811 16 +35048 13 7 +11096 47151 17 +7276 9723 11 +28453 6156 11 +48918 54286 8 +8816 55777 9 +18351 13289 16 +27840 40640 8 +21419 1285 11 +2550 53741 7 +10732 51743 2 +46029 3589 3 +12927 34838 9 +47385 50844 11 +48998 35906 8 +7553 22987 1 +34019 16868 9 +34003 16715 9 +9246 46577 6 +31042 47806 10 +22663 22302 8 +37952 46362 17 +4711 290 6 +31765 59438 16 +8376 23932 13 +26437 26226 14 +43408 54353 8 +34510 25724 9 +39700 46473 12 +40737 42344 17 +44466 11484 9 +31792 56714 8 +39893 52389 14 +18494 59887 16 +20204 18317 16 +44217 24204 9 +7654 52285 10 +34254 11040 13 +14254 34607 12 +25436 4416 6 +43776 5070 11 +43445 1411 4 +53356 45621 14 +59179 7319 8 +50475 7061 11 +10772 24850 12 +22024 43635 5 +7149 37038 2 +23135 26466 9 +11528 52864 10 +55272 19912 15 +30187 7352 7 +51021 9709 10 +13174 48270 9 +41997 12515 11 +36955 7826 5 +43540 27069 5 +24292 18327 8 +2073 43527 2 +22518 4543 7 +50835 58219 7 +58156 37708 8 +48553 39630 10 +42757 42294 9 +28130 51628 7 +38843 36011 10 +47384 56747 7 +22392 59104 10 +17079 22670 10 +58266 47442 2 +30908 36344 10 +19159 45683 9 +54421 45781 3 +36076 58064 6 +2169 44114 10 +23747 22865 7 +29127 3013 10 +7346 40248 6 +56273 53680 10 +26674 15726 8 +38081 34747 3 +17543 12812 8 +34258 32737 14 +29791 44470 10 +41458 55560 9 +14681 46133 16 +34497 27640 7 +11058 11187 1 +10227 25803 5 +57874 42076 17 +5589 59935 16 +11384 306 7 +3429 46333 4 +52385 46603 3 +50556 25124 7 +54484 3194 6 +40795 36419 11 +38624 15728 14 +11218 1881 8 +10057 9985 8 +51857 14204 11 +5355 17630 8 +17024 50112 13 +56266 23410 9 +31721 25807 10 +19824 22905 13 +15734 27086 6 +54611 8714 10 +52518 58234 7 +23172 9737 2 +34036 7943 7 +4656 41795 0 +32069 24230 13 +29932 48725 5 +10342 28318 2 +16676 58886 4 +5267 48859 9 +32121 31199 9 +3271 15467 13 +46483 30838 11 +30315 34223 12 +32269 31249 5 +28523 32319 12 +9500 5841 8 +27711 18200 9 +32276 14668 3 +59080 52761 18 +25784 13764 4 +27949 2626 11 +51382 57803 8 +54537 56692 12 +1374 27954 7 +41801 35727 13 +32250 797 6 +9717 47023 2 +7026 55220 10 +36717 12372 4 +17806 10563 1 +24251 33185 5 +17721 14399 14 +29326 22272 12 +39920 2508 9 +44919 25594 8 +38980 13170 12 +54822 25718 2 +27025 47766 10 +12735 46734 10 +32565 49529 7 +45755 47382 7 +12205 46422 7 +58331 18149 15 +41979 25986 17 +17983 15456 13 +19032 9392 8 +1648 14875 11 +13527 51716 11 +32522 54427 10 +40200 3493 8 +34624 7169 7 +9221 4528 8 +7550 10711 16 +42073 35956 12 +34566 41977 5 +8382 15021 9 +43813 23572 4 +48813 8737 8 +37939 40708 9 +52218 19811 8 +2366 27170 1 +50447 57890 3 +41048 8666 11 +2120 1944 12 +245 23371 10 +7397 13970 9 +25070 1776 15 +41902 21520 11 +11584 11215 9 +6883 22002 3 +50145 12389 18 +55637 3917 4 +23697 34116 8 +12791 11535 4 +56264 22826 9 +14240 4730 13 +13019 8161 3 +9831 57548 11 +32825 16284 10 +2293 55500 7 +41999 30364 1 +52939 5432 6 +33145 5845 5 +7255 30462 14 +492 727 10 +59762 58807 6 +48324 20196 12 +30253 7450 12 +35116 58713 6 +34034 40353 13 +28839 19774 2 +32009 59291 5 +53623 34583 16 +52093 32601 11 +23735 25141 12 +25753 56999 11 +8450 27061 10 +55900 43641 11 +56816 39415 10 +24681 53951 9 +12212 4451 3 +22855 54691 16 +48505 11158 12 +20691 5650 8 +41554 40346 6 +17316 28304 11 +7068 33831 5 +16285 464 0 +34863 22465 14 +9142 45094 2 +17302 3839 13 +8273 21516 9 +28305 38686 0 +55010 47032 11 +40953 8205 15 +2872 55609 2 +29666 40050 10 +18517 5798 9 +12455 11930 12 +52412 2258 11 +57116 11519 10 +964 56868 5 +25078 22480 7 +57726 4126 7 +20798 52513 7 +34557 53138 7 +5785 6967 1 +44923 7741 11 +2122 47850 2 +30130 19000 11 +16515 49853 9 +24373 49780 3 +27294 39124 11 +53590 24314 12 +31497 45637 7 +6514 5899 13 +57377 21690 5 +59308 3695 8 +32804 57020 3 +38166 14748 8 +45568 47799 3 +17325 29762 11 +38991 27206 3 +1349 14661 6 +12067 23985 14 +56253 3223 14 +18978 2003 6 +24042 17234 12 +42239 36292 6 +40680 41505 12 +43909 10417 10 +53249 9421 10 +58512 51228 2 +3694 39347 4 +24463 11455 7 +33699 39354 10 +23716 11676 3 +50919 34831 7 +35726 24229 8 +28530 4161 18 +9584 48689 7 +6824 34271 13 +54865 54850 9 +9483 23354 15 +27366 8981 9 +37439 11788 6 +22501 33588 15 +27514 32191 8 +35799 38582 6 +58675 28382 7 +5064 45177 10 +35047 44426 9 +51851 54190 11 +20338 41079 8 +50471 18010 6 +45760 1686 6 +27405 25557 11 +15442 9866 8 +42039 48683 4 +1960 4069 10 +58117 46555 8 +59947 41100 5 +46760 27615 11 +32927 45575 15 +8580 12995 7 +58676 34759 8 +38697 18657 9 +9860 54577 11 +823 10963 16 +30209 25993 4 +53801 49142 12 +52547 20187 8 +56108 34094 12 +43341 48589 16 +37759 17669 1 +21429 38701 16 +35548 37562 7 +16858 40956 4 +6363 14400 11 +27583 46449 3 +58529 54505 17 +13889 28975 6 +57604 14888 11 +3522 31633 8 +46730 23152 12 +38709 39973 10 +54355 28352 10 +47102 42184 3 +27968 59840 9 +19413 15854 3 +28132 51293 9 +17855 57354 10 +10659 48922 4 +57433 50565 4 +14162 7559 14 +52642 36438 13 +10019 49886 13 +37736 11205 5 +16375 1569 12 +55666 35597 2 +27133 47479 3 +52467 16815 18 +4630 43741 17 +25925 10064 12 +23005 46731 9 +36345 45317 15 +51986 12794 9 +19596 12093 11 +14674 58902 7 +45888 31622 17 +40820 32507 5 +17431 16842 9 +34525 43720 9 +59576 48403 5 +18290 9319 5 +13529 28729 15 +25550 17821 6 +43157 33678 12 +49432 25587 17 +38132 39834 13 +6691 5535 12 +28244 12841 8 +24005 58225 11 +35898 38180 6 +54896 50223 13 +496 13728 14 +54325 49958 9 +51271 35818 13 +47349 43611 16 +56062 19359 18 +14651 58416 5 +39350 3617 15 +48240 22206 7 +28769 11621 3 +43844 7381 10 +56 51644 9 +38715 13836 5 +1870 52766 3 +51990 9006 8 +26754 5830 6 +57394 34504 11 +2587 50362 4 +11964 604 7 +31185 39161 4 +19135 38308 12 +39875 58020 12 +27305 3587 1 +55972 20632 2 +57891 58605 12 +40598 50474 4 +6644 19053 7 +39338 41851 9 +35973 43405 9 +17452 6795 8 +37531 24150 9 +50493 46828 10 +28018 50226 10 +54659 41655 9 +2930 56863 12 +52297 35337 13 +15733 5392 9 +13115 2411 9 +39806 26793 13 +49526 41056 6 +4530 53510 14 +34446 16834 12 +11367 1028 9 +11116 58482 4 +47931 30638 13 +48395 56594 9 +33244 16193 3 +49791 26268 4 +13848 35406 9 +49782 47215 6 +2038 760 8 +39594 29030 2 +34486 39843 1 +43845 59460 10 +13106 52200 5 +5879 23855 10 +48280 37923 9 +37961 47383 10 +37474 1512 9 +19536 59205 12 +18950 38486 12 +46341 36370 16 +51279 40266 7 +46238 21767 10 +5286 18297 4 +43018 48144 15 +20269 13587 14 +54671 30573 9 +9092 58860 10 +55908 18148 6 +47619 7373 0 +34281 44283 8 +14489 55152 5 +19775 48235 9 +35552 29085 3 +28806 47199 6 +20595 56167 9 +29007 38347 10 +9652 2112 5 +35847 23294 11 +28174 34195 12 +32469 27429 4 +44793 38246 12 +50266 45079 9 +15155 20202 14 +18991 19311 4 +53968 56977 9 +9620 55512 9 +15661 55304 7 +25487 43818 4 +25951 47302 10 +38233 44026 18 +31080 18238 14 +13494 746 10 +37841 20490 4 +15966 9063 8 +57728 58677 10 +54618 406 7 +3014 33843 8 +53578 5883 6 +45178 41889 15 +7383 10409 4 +22494 38679 10 +14221 16508 2 +30862 53317 17 +48064 40912 7 +54699 45821 10 +26485 22963 4 +36226 48060 12 +48331 43331 10 +50416 58880 12 +30839 2423 9 +49900 33214 6 +58277 3925 11 +45697 52401 15 +1970 170 14 +48035 58288 10 +19519 24831 10 +47610 19884 3 +54928 19874 10 +58548 54277 6 +24459 6572 15 +50218 8157 2 +47739 51725 8 +50078 21261 12 +53359 16677 8 +16538 35907 7 +14092 51446 6 +31697 21694 17 +41329 48 18 +17319 17338 14 +52322 20308 16 +5337 20056 7 +51244 58522 14 +24521 21926 16 +529 23113 9 +53142 50126 16 +22983 54200 11 +14190 28398 10 +39798 31077 12 +27321 59948 16 +37680 15780 11 +30437 29989 17 +43255 16178 3 +7414 26723 8 +56126 15803 9 +47567 45845 10 +58930 15868 5 +47472 9158 6 +50412 11596 8 +2646 21115 10 +35904 53351 5 +27842 45335 12 +57434 2598 16 +53441 2154 8 +56590 16160 8 +32880 41513 3 +2488 15516 7 +26406 23741 1 +2392 8212 6 +9425 33050 16 +17392 13904 9 +15641 23481 8 +38262 19694 6 +59550 44347 5 +20254 57459 13 +53992 30822 11 +19737 11253 8 +24426 30522 7 +45279 4099 11 +20044 55897 11 +40481 14645 11 +40422 47403 14 +16551 52651 13 +21647 40945 11 +19759 21840 14 +41704 6492 5 +31757 31648 9 +55948 2915 7 +46208 3121 12 +36330 39346 5 +46990 31821 10 +19111 59649 12 +31482 55527 6 +34551 233 5 +30391 47489 9 +8004 56385 12 +41862 27996 6 +6153 973 14 +29881 15916 10 +19126 21114 14 +31222 10810 14 +39134 14971 9 +39697 23496 11 +37842 45429 9 +24568 9542 9 +106 56222 8 +34692 24381 7 +43199 36776 13 +10159 57939 6 +49846 14214 12 +2816 24244 7 +12721 53445 17 +8582 56631 4 +7953 40165 9 +50779 14629 5 +27399 16643 9 +36020 31661 8 +57057 30080 1 +59500 13908 7 +51188 29462 6 +57288 44236 9 +55498 25809 8 +19734 54234 7 +48375 7437 15 +39412 22182 6 +24833 46429 9 +58409 1982 9 +39510 55608 9 +40349 52958 10 +39856 59190 5 +47441 2882 3 +5075 48579 4 +48507 42608 6 +50812 41037 4 +43159 47039 10 +56704 55150 1 +16059 11540 15 +53753 27645 7 +34889 29267 3 +50629 29794 4 +38661 37495 6 +1780 58038 8 +48880 3920 7 +20100 47696 2 +52697 12718 5 +8265 24950 14 +42970 959 6 +45145 33033 5 +58858 32382 2 +58684 51564 5 +955 14774 10 +48565 53788 6 +12456 57691 6 +9799 43456 11 +29546 54617 6 +41858 44454 2 +53888 24203 6 +23383 40654 13 +9368 1128 5 +26600 2210 15 +33103 1705 11 +22960 7391 4 +23173 47114 9 +51155 20130 13 +4446 57673 3 +34674 4113 10 +49065 12814 3 +42979 43618 15 +2029 42946 12 +2649 37332 12 +12482 7614 10 +683 17713 9 +36653 7028 13 +6898 35589 11 +20832 49694 9 +23253 36675 12 +55211 17858 17 +48387 25454 9 +30812 36610 14 +18760 12573 1 +27499 56317 14 +33998 51812 10 +18146 23981 14 +27644 1088 10 +23424 37267 13 +47008 18108 11 +2819 49 7 +43652 55702 10 +26768 12947 6 +353 26517 12 +18095 5566 7 +53760 14192 12 +8928 11246 17 +10361 57716 11 +14497 7510 11 +51437 4095 17 +39366 5261 12 +33727 12017 5 +6001 16906 1 +28918 41281 14 +53131 52994 11 +15937 37884 7 +17663 19697 6 +38156 21530 11 +35398 9135 10 +23847 16043 2 +5884 26810 6 +10294 13683 10 +32487 31629 10 +7504 52259 9 +33201 9759 11 +35305 4033 9 +38428 19308 4 +4564 4067 4 +58627 40777 12 +1164 39959 6 +41796 14402 4 +33921 47935 1 +10699 13604 3 +43353 33747 7 +10333 5488 5 +53028 33445 11 +41007 13088 12 +59715 22666 7 +25661 26478 11 +700 41104 5 +655 57937 8 +29424 14264 8 +14287 49642 9 +39260 20997 15 +57112 34469 10 +49450 21431 7 +47738 38674 15 +11643 21389 13 +560 25361 11 +13468 6802 6 +18973 42331 17 +8902 48528 17 +34205 49083 10 +58688 37657 12 +32751 36492 10 +2348 55470 10 +12914 50082 15 +48740 46889 15 +11728 48120 5 +36915 41780 12 +2040 45679 9 +10530 13911 0 +43119 49943 5 +2269 12209 1 +8620 24423 15 +43929 14405 10 +6512 29861 17 +18840 5791 11 +53255 6500 3 +23180 32794 11 +19398 21754 10 +4053 49963 11 +11009 49015 8 +11264 23340 5 +41189 15017 2 +8444 21091 16 +30776 19314 11 +11616 49607 10 +58796 53207 11 +33197 43517 5 +31737 31880 17 +33277 38321 3 +5745 51662 15 +24676 33379 6 +32729 34829 14 +12274 43827 3 +42803 8434 6 +32716 15212 16 +44840 14949 7 +2304 17969 12 +5228 7558 1 +34959 29717 9 +24183 42002 2 +50267 46866 13 +1137 7459 4 +41794 33986 5 +5309 13979 13 +20761 33849 6 +32115 14365 12 +17194 43180 11 +47892 17290 16 +38912 16610 9 +51651 52956 3 +295 9993 12 +23303 9664 4 +37523 39883 12 +31403 54804 4 +6489 3310 12 +2407 52073 5 +30775 29754 12 +22125 15420 13 +6400 3753 4 +24634 10591 7 +26389 26323 0 +4279 23275 9 +35983 23794 10 +37032 7434 14 +30712 21755 15 +9405 28138 13 +2640 29452 16 +32451 593 10 +28349 22979 6 +30910 34216 13 +12516 30569 2 +45474 36644 6 +16391 14206 8 +21229 40405 4 +7966 57635 6 +57014 10264 3 +33554 58399 7 +32629 28972 14 +36591 14968 9 +12340 8220 15 +5472 16069 15 +39143 39943 7 +12052 31685 5 +43230 51600 7 +21487 53334 10 +22202 20514 2 +28004 8145 13 +14901 41640 3 +46406 12405 8 +48221 1909 8 +12655 33853 13 +45248 37272 10 +44133 28442 6 +53405 55270 8 +22230 10124 17 +47540 51492 14 +23171 13472 11 +25102 45979 9 +31163 11845 4 +7667 17605 10 +8931 27918 15 +27448 33725 10 +47724 6375 10 +18141 48712 12 +28655 11869 6 +15056 16831 11 +45161 25523 11 +46928 4684 15 +48832 34242 12 +17464 23554 3 +43468 9173 1 +9916 55881 6 +50046 22415 10 +52676 5454 12 +1253 44313 4 +49205 49897 5 +26605 20636 17 +5997 10430 11 +24256 35221 11 +52135 44632 4 +13373 43272 10 +44517 10372 6 +19915 40312 0 +9864 21709 4 +14866 14459 16 +58348 47449 14 +11505 39936 6 +46956 47887 2 +8884 35797 8 +27794 1186 13 +26395 55860 11 +51632 44441 15 +2224 16443 8 +47035 54457 3 +38914 30154 7 +24648 54506 5 +20399 28787 6 +26393 43387 6 +6384 4845 6 +11743 8270 5 +38930 52469 17 +23472 5907 4 +47226 41527 9 +9346 44711 13 +1782 21170 9 +14417 49833 10 +45654 45468 12 +37247 59101 17 +7261 30256 6 +47962 54797 9 +56860 49950 10 +14622 38032 13 +18380 9039 4 +21134 11672 12 +4662 27424 6 +53470 10146 10 +37379 28894 6 +22446 47812 2 +40899 39070 10 +49146 42306 13 +29899 2715 7 +23440 17068 15 +39073 33690 14 +51112 8514 10 +20780 8903 4 +41140 25976 13 +24512 26797 7 +29228 48973 12 +35866 3802 5 +22805 24911 14 +53211 9360 11 +16236 40808 9 +54136 25954 13 +32639 55180 15 +19702 23885 6 +54153 36397 8 +24454 24509 10 +16004 9188 14 +20578 31818 17 +5119 19081 13 +41393 8336 14 +57222 26313 6 +23721 19190 11 +39302 24907 11 +7280 47047 10 +22060 12032 16 +18020 43633 8 +40101 2656 7 +10033 19187 11 +218 28933 13 +9330 24196 8 +9224 15849 14 +15125 50944 3 +17428 39836 7 +3637 32088 9 +3738 39004 10 +48473 4540 11 +16718 39436 6 +47793 17720 16 +48021 10692 9 +46841 50465 3 +4153 23541 2 +824 41297 14 +13919 59187 2 +2986 45534 12 +12225 10211 8 +16951 4007 13 +54156 10325 5 +56762 21773 4 +23972 3560 6 +10783 44079 2 +1827 44951 4 +44025 390 11 +52576 7506 9 +30020 23511 6 +11091 46633 8 +58039 50194 6 +10209 42640 13 +20864 42548 16 +41090 55202 3 +14105 50172 12 +54495 41615 15 +22280 15419 8 +44806 49012 15 +40185 28323 3 +45199 8146 14 +20553 32059 8 +31665 13936 11 +21031 5772 7 +6333 4132 11 +51318 14461 9 +45159 58931 10 +1517 4610 2 +33827 15864 8 +2720 34126 12 +3239 32024 6 +49858 41022 8 +45779 36084 2 +15167 5744 11 +15089 8657 13 +26947 38565 11 +46067 10585 9 +21339 6965 11 +22677 33989 7 +1365 56862 7 +40954 16145 9 +25770 10577 15 +622 20275 6 +30002 27487 7 +32395 1228 13 +41730 22873 10 +281 59245 5 +49656 56753 18 +44061 21297 17 +10382 33152 17 +25056 21591 13 +34137 40247 8 +16171 4771 12 +22937 19344 8 +38446 13722 2 +47193 20948 11 +33542 15251 9 +24727 18373 15 +42676 53186 12 +22044 30428 9 +25755 52426 6 +26874 33647 6 +31754 47568 13 +53674 19649 4 +41757 59976 12 +5810 22433 15 +20198 10634 12 +39067 53135 7 +5725 18932 13 +59907 3631 10 +35255 28522 8 +4666 56088 7 +28128 36147 6 +53755 30445 6 +13066 37978 1 +28941 16829 18 +25161 27550 7 +1295 27174 12 +37998 13672 15 +4080 30516 10 +46023 3236 16 +21414 37417 10 +58455 46111 7 +7360 11343 6 +31772 33303 10 +3721 50457 9 +56887 24984 15 +24125 57971 9 +34206 32951 1 +30659 21633 9 +9056 42163 7 +21816 12045 15 +22707 24880 4 +55937 39865 11 +15038 58260 5 +32615 18086 15 +42893 38561 2 +6103 52229 4 +39928 22016 10 +7663 30693 16 +40944 44276 1 +26382 27537 8 +21168 1617 7 +46782 58887 2 +54939 18264 2 +29332 14149 10 +46215 34936 9 +27391 59847 9 +31246 21383 12 +26256 31424 5 +11393 32378 6 +50207 44198 2 +11904 14141 15 +44556 58498 9 +58120 51339 6 +40757 27657 7 +52098 57779 7 +13099 33483 12 +12267 55100 6 +54406 22244 8 +41033 2413 17 +45419 30858 8 +55056 1756 3 +16388 2110 10 +5387 56030 14 +43303 59166 6 +9443 6736 4 +39153 14404 7 +4272 39748 13 +56054 13285 8 +33382 26601 14 +15476 15117 11 +38157 36179 8 +12120 45028 11 +10092 28888 5 +59651 21361 9 +21937 59326 9 +32529 26776 15 +57478 7744 8 +3623 55069 8 +33200 34546 11 +49639 24162 6 +17101 45613 5 +7259 9113 8 +4524 28288 10 +26872 8564 6 +39325 36295 6 +2917 52667 9 +7937 33266 7 +29835 32185 13 +32485 44856 3 +42989 58625 8 +10524 16163 9 +17840 6846 4 +17198 22639 5 +51089 40113 15 +16578 36843 11 +1734 23028 3 +9379 6901 10 +25833 34981 14 +40628 41690 15 +26893 432 10 +40161 2134 4 +32587 34563 14 +25182 35575 10 +55899 50625 10 +19138 34842 12 +31761 24394 9 +24294 8018 6 +54456 46934 3 +11634 34911 2 +5537 10576 17 +41747 18788 9 +44068 42143 10 +14395 462 7 +55954 2607 10 +5774 42205 7 +9446 17813 13 +58192 15586 9 +52414 26314 13 +3725 59668 10 +37799 29711 12 +27270 31314 1 +14912 1626 6 +17164 26687 7 +7312 19969 9 +42901 54446 12 +58150 36820 16 +54912 52571 13 +6018 40094 9 +40499 22132 11 +32101 10601 5 +46264 39840 9 +2767 55898 5 +31018 174 10 +26939 36416 7 +1930 6059 3 +57666 979 8 +13095 23791 17 +340 19674 8 +53189 32379 3 +23313 45758 5 +44493 43662 1 +31303 17903 15 +9074 35750 9 +58743 41419 1 +34549 5832 15 +47598 2586 2 +57614 20484 5 +32180 31341 6 +34741 34671 12 +24090 38551 5 +34663 12797 10 +2273 37956 10 +28029 17019 14 +3877 5022 11 +54172 25042 7 +42009 24703 12 +43809 22665 11 +49337 32365 7 +5464 48158 2 +48734 58400 12 +7122 34428 12 +45542 33859 15 +33112 45309 6 +46475 17116 11 +12809 40357 8 +23850 6753 10 +3974 13935 8 +16595 11796 8 +48863 4616 4 +36296 52351 10 +1048 9957 6 +43138 11459 13 +54342 40450 5 +44568 10380 8 +2440 13934 8 +42439 43911 9 +10988 30343 8 +44518 27879 1 +40571 57948 9 +6459 16792 15 +12593 30928 8 +28780 33213 4 +19116 49990 11 +15342 22131 10 +21973 35814 7 +17144 33424 15 +13178 26290 14 +1687 20453 12 +18127 19929 14 +57272 43092 1 +48703 21708 12 +10796 50653 7 +38669 8003 7 +24161 41645 13 +11021 27489 4 +43300 46113 2 +4145 45281 2 +17621 50275 9 +8726 48238 8 +14798 44959 5 +49510 31155 9 +38052 27483 10 +57501 7588 9 +26894 43246 8 +15350 53858 10 +4879 45423 14 +11738 2101 2 +23542 30415 17 +56121 19662 15 +44113 1697 2 +31210 12727 9 +29834 58720 7 +10385 16881 14 +5430 58901 15 +4157 17335 2 +18402 42123 13 +24949 38550 16 +19530 42291 14 +31598 24188 4 +44667 47658 7 +10943 49750 5 +1840 53210 11 +38691 21672 7 +35166 33844 4 +28165 28579 5 +6805 16374 7 +26808 41053 7 +10416 56533 1 +5815 7698 5 +19610 20961 6 +53220 1098 10 +58715 44092 9 +1945 11457 9 +50734 21055 8 +18257 13723 15 +967 28976 8 +4748 49101 2 +33034 5649 9 +35615 44417 10 +18735 55591 8 +56443 10788 16 +47470 51449 4 +53013 53280 11 +25983 5324 5 +57347 11516 13 +643 23634 6 +36379 54814 8 +18767 52780 5 +43042 5626 15 +44045 15289 8 +20084 11675 9 +51688 46465 12 +30153 56985 15 +10395 22115 10 +14413 7240 9 +58010 38300 13 +49408 37779 11 +45567 17765 13 +50124 47072 9 +34229 49534 8 +58004 205 10 +39192 4492 10 +51963 8229 7 +41352 16959 5 +2710 39550 7 +51767 26155 10 +30880 41949 7 +12309 7157 17 +35527 21706 8 +51130 26666 13 +25620 7753 8 +9382 7523 9 +55909 47732 9 +18461 51133 3 +45511 17641 8 +45266 13927 9 +19563 56756 13 +17461 24626 6 +2207 7973 4 +26232 2740 10 +26119 18648 13 +8968 1559 12 +46536 10446 14 +33311 14081 11 +42449 42758 8 +4014 55996 3 +34240 17307 11 +48979 31907 13 +27119 14594 13 +9700 58644 8 +29460 2233 9 +56791 25836 3 +59364 14531 8 +49992 21613 13 +36099 42423 11 +20539 26497 14 +18254 37266 8 +608 14211 15 +49162 52831 4 +35890 58233 11 +30007 44567 4 +1085 24225 1 +18017 6394 2 +38485 37432 3 +52724 40833 6 +28576 17332 12 +17984 26250 2 +275 20006 9 +58992 39208 9 +22620 40382 5 +14007 18355 11 +17327 6029 6 +46792 23015 9 +28413 50265 8 +9286 5255 12 +14762 21107 13 +46587 41966 8 +30568 34809 12 +39252 21472 11 +55991 51052 0 +21732 56651 7 +52460 56600 15 +26745 7433 4 +48452 32288 9 +11206 56553 11 +24835 1176 7 +39396 103 11 +5414 3197 6 +20449 8979 7 +19909 27219 12 +24772 17283 12 +21392 39809 10 +28148 49466 14 +29392 11508 7 +9340 43665 5 +1518 9438 15 +20905 21071 9 +57851 36393 7 +55129 34477 9 +31521 50497 11 +45925 44182 18 +8423 24380 7 +21880 43209 5 +12166 2835 8 +1241 47899 12 +45765 14683 12 +18287 10131 10 +50599 26329 6 +12938 27184 9 +45612 44893 3 +30412 34306 17 +31911 14370 6 +14897 45537 1 +36873 6728 15 +48008 30661 10 +11478 30532 15 +35272 53067 8 +32229 38615 8 +39034 24892 9 +40981 28960 17 +49955 12444 11 +24700 20226 14 +55496 4217 16 +32334 59906 6 +3430 41750 2 +50729 10130 2 +19541 39505 9 +24078 15137 2 +13922 4052 10 +27857 74 7 +57054 37340 14 +9465 12084 12 +25887 10638 5 +3940 21914 12 +7971 31976 6 +35942 6165 2 +29839 9533 8 +45855 57091 1 +11103 34098 17 +40759 12005 11 +35416 19505 9 +24529 15652 6 +56796 21465 7 +38608 50006 10 +4843 59244 2 +54752 36454 6 +12798 1157 8 +59062 33618 10 +13139 11180 9 +11495 16434 8 +29300 6121 12 +57432 10958 14 +3503 29279 12 +23279 29790 5 +39552 34978 9 +33791 16228 10 +19378 41510 13 +57973 58075 10 +31216 40623 7 +44461 10253 12 +39257 23363 13 +56113 53959 5 +45982 28217 8 +14780 59927 18 +58377 13073 5 +21970 32961 5 +17157 44651 9 +34315 7013 12 +51427 29415 9 +34282 42155 9 +55896 45403 8 +5077 48464 5 +54780 19313 11 +30663 57346 8 +38577 59854 6 +58268 10805 5 +45593 29541 6 +40090 12680 3 +33903 11149 13 +24813 14806 12 +4529 9193 7 +50748 35611 7 +56761 23706 9 +39444 35151 6 +53913 42437 17 +24992 44966 5 +6140 45082 15 +1836 42526 6 +28741 36584 10 +12707 33918 3 +5844 56608 0 +6533 42493 11 +32482 53675 6 +11474 31664 12 +55977 56752 8 +13783 3691 5 +10368 55817 2 +8362 17905 7 +28828 45598 2 +9560 34801 16 +2222 32470 11 +22488 49568 8 +59742 51164 10 +55551 58802 11 +41675 23564 8 +41594 2830 10 +14068 4467 9 +25279 27349 7 +39662 54248 11 +32479 14832 10 +59494 19584 7 +37233 50443 16 +32610 59969 12 +41870 14324 13 +16833 32081 10 +3114 54075 10 +51347 11024 12 +49186 43126 4 +20896 55003 13 +46919 30708 5 +5183 44317 9 +15769 33054 6 +2593 34917 10 +32574 19641 9 +11514 26264 4 +39841 59216 13 +14394 9407 12 +54198 8790 11 +5094 37995 4 +47762 7275 10 +4169 28606 9 +51343 37308 8 +1378 3734 3 +5341 591 11 +41520 15316 8 +20917 45701 2 +26741 30192 8 +18500 40381 17 +56874 19877 16 +53745 47066 16 +45842 43887 9 +40307 52445 11 +52500 37313 14 +1214 31910 15 +39509 50181 6 +33041 851 13 +57191 43933 3 +27632 50561 8 +18620 16094 6 +26663 8802 18 +34614 28216 8 +56170 15444 13 +50825 51194 9 +44577 35706 15 +41488 33381 6 +30735 2061 15 +54328 18206 2 +23728 57727 0 +45690 9595 5 +21449 54812 9 +40671 36787 9 +38365 40882 13 +2281 22812 6 +17668 56134 11 +44628 58092 8 +23959 5233 15 +24330 57120 5 +55412 13753 8 +3291 58247 3 +56326 58735 10 +32399 18363 3 +26580 16115 16 +5269 10298 13 +27096 44250 14 +43081 45256 5 +9706 24666 8 +39186 16089 6 +26945 49697 8 +6884 48122 12 +45012 37468 8 +39535 23422 15 +31079 33676 7 +18407 35369 6 +42482 43970 18 +10896 21313 10 +32694 8009 12 +5492 8301 18 +14947 51946 7 +47908 51280 10 +26732 4822 7 +32755 56743 9 +6326 19525 7 +16378 20131 7 +6881 20321 7 +31547 26763 11 +28524 31197 3 +31049 2309 5 +14915 6992 11 +21652 29297 9 +38494 16027 2 +51311 25345 12 +21864 59910 12 +22936 21135 8 +31705 7031 9 +44697 34745 8 +16597 36306 17 +20947 6617 1 +55582 49479 4 +22317 54094 1 +3616 23306 12 +49673 49272 12 +23270 23827 9 +50775 18344 9 +27729 25912 10 +33604 46340 13 +11269 10498 5 +41682 21354 5 +34344 31696 9 +35210 43196 9 +51245 3711 11 +30309 26265 4 +57853 50740 13 +981 44226 9 +53400 38510 16 +36989 26934 11 +38831 2412 6 +48046 15806 11 +42011 39370 16 +5259 5362 11 +21568 53149 5 +6005 55870 3 +29584 36133 6 +10565 23820 4 +6144 16849 5 +9667 5850 5 +23849 8751 16 +33672 29733 9 +53199 59067 9 +35800 36472 7 +34798 21673 3 +54980 46641 7 +55973 19127 8 +45934 49347 12 +2925 58941 13 +11774 49304 2 +39368 29483 7 +1509 26116 14 +16394 30060 14 +341 50591 7 +32130 41515 3 +30492 30082 7 +7617 39156 8 +45302 2194 9 +10511 57653 10 +31550 20054 16 +56963 27975 11 +12022 22777 3 +31258 55148 7 +28045 27761 10 +48260 52397 5 +15638 20825 15 +41389 22066 6 +26049 56399 13 +37992 10812 9 +2610 24283 13 +8578 37115 10 +54795 3214 9 +7034 44195 10 +18666 40259 17 +9524 46719 8 +19124 47816 8 +24865 19400 3 +19763 6112 13 +4931 42287 5 +34965 1274 14 +44154 49172 13 +15022 24028 6 +52270 52559 14 +1603 59285 10 +42349 26532 8 +49617 5680 16 +12051 15563 13 +48714 13969 9 +16359 5221 5 +25697 36684 4 +37124 2068 11 +10331 52379 7 +41910 50777 11 +33226 18777 18 +59338 43581 11 +36560 991 4 +9131 10370 5 +22763 45880 8 +24786 14585 3 +45063 1884 10 +55638 22917 6 +50965 18481 13 +56591 55691 16 +22313 17205 14 +27643 50751 3 +52197 29153 9 +17336 53711 5 +2337 29371 11 +18877 9016 10 +43139 6768 5 +6188 21940 9 +56174 20055 2 +9126 23810 9 +58721 42489 9 +15847 46783 5 +57037 37781 10 +14941 25862 15 +26863 171 4 +37753 38783 14 +5166 20297 6 +39720 29841 13 +31563 37151 6 +26354 23041 9 +54676 41010 5 +83 11429 6 +35311 28622 1 +32142 21798 4 +25054 24431 2 +44979 27633 0 +48726 54040 16 +2205 57762 5 +18540 4764 2 +52247 16954 3 +31443 19349 15 +20559 24375 15 +54796 49814 5 +41307 9637 7 +55176 26142 3 +39174 42196 17 +53659 53313 15 +5406 26991 5 +3398 12550 9 +56334 55918 11 +14717 32709 2 +8543 40507 10 +51634 12853 13 +23990 41677 16 +18279 9183 7 +2903 53928 7 +15745 37393 10 +20267 21355 9 +15440 25231 5 +1585 7000 17 +34272 38945 9 +3761 32343 9 +31001 37997 2 +48999 29564 6 +7727 18879 14 +20843 26961 1 +42876 10764 12 +32509 48475 16 +17539 21993 3 +7253 42765 2 +35628 6268 9 +9132 50833 18 +39807 20941 8 +49840 15347 5 +58144 58965 4 +55285 57408 4 +47164 17403 5 +43617 6964 11 +5366 24895 5 +18511 18103 10 +39473 1393 11 +27393 26168 8 +29393 42303 11 +47358 39064 15 +8097 59316 4 +32591 19607 13 +48494 43231 12 +19865 7516 9 +51626 9797 8 +8364 55312 10 +25591 21181 6 +14627 50017 14 +53536 30827 0 +47826 14232 10 +2395 6829 10 +20041 43082 8 +1267 30451 16 +42365 14450 11 +16473 53451 6 +2459 59940 6 +12871 15363 4 +28566 6871 9 +2387 43857 12 +57199 37672 11 +10419 30724 8 +28668 49079 8 +49925 17889 17 +8290 34591 15 +26851 48586 12 +9029 1927 4 +50102 11164 16 +30726 43930 10 +37195 43306 14 +45619 13327 11 +13049 11228 10 +50746 17687 16 +15406 18722 17 +28761 12470 14 +8887 32321 8 +47371 23051 7 +53475 56869 6 +32082 34301 15 +13796 39758 5 +19497 42940 10 +56386 20350 16 +21930 35088 11 +5829 4508 12 +30009 22654 6 +30300 179 3 +4 17225 10 +90 4303 13 +54758 29915 7 +17939 11629 13 +57232 46765 12 +27118 35435 9 +37024 23076 4 +59253 5172 11 +10479 7555 2 +29403 43655 7 +20354 22370 8 +41121 41015 5 +44831 12652 4 +19976 43753 8 +23495 23640 5 +43427 35283 16 +41848 29811 7 +45249 6504 13 +44825 19133 9 +40201 15515 9 +5038 43505 10 +52489 24783 4 +9315 1947 3 +50294 55462 14 +56746 25339 13 +31973 20060 2 +41096 44964 9 +15204 40210 8 +52903 32235 18 +26025 10178 16 +18819 3468 8 +56518 9815 8 +24951 26330 7 +37287 55564 4 +48199 13989 6 +48537 37951 10 +36371 50685 1 +43027 36395 10 +20957 53102 13 +27849 18969 15 +53934 44391 8 +23302 34627 3 +43065 57848 8 +51720 8006 12 +3168 2535 11 +2090 15861 15 +47124 57002 4 +49641 46516 1 +22216 10592 17 +49275 52123 15 +8051 15600 1 +45988 23702 16 +16048 55801 12 +24273 16636 5 +23321 2179 9 +6948 22959 11 +48713 40244 15 +50248 9375 13 +19182 25871 15 +53464 1447 10 +59716 7985 4 +3768 17171 6 +2058 43287 3 +36408 9582 8 +30376 31439 9 +41109 53132 6 +55317 36446 7 +14120 58778 16 +19583 25845 4 +23393 50187 9 +27396 29947 10 +14783 23915 12 +49912 29116 11 +15931 7773 13 +30019 21581 12 +37200 34280 10 +15842 9000 9 +14307 32635 8 +35865 51192 10 +45751 40325 13 +34413 59659 6 +13949 6420 12 +25761 9491 12 +40246 24331 2 +10863 20136 7 +6338 3615 12 +55157 57190 3 +4780 5612 4 +6790 13625 10 +41887 23012 6 +13260 12493 9 +22133 14471 7 +7920 31169 3 +4639 49524 7 +35158 3128 6 +26328 49823 9 +50724 50116 17 +25792 24211 16 +34942 8821 12 +47854 47948 13 +35382 46723 7 +33029 19761 9 +11145 31182 12 +3827 48695 9 +3681 23694 11 +184 59529 4 +35216 38798 7 +28911 14554 18 +2184 32562 3 +24830 17882 14 +55242 1868 0 +24774 49841 9 +58481 44984 7 +39442 31844 15 +32628 45506 10 +33817 26015 7 +5441 8780 15 +44805 45749 11 +13797 53600 16 +6739 392 6 +2823 57024 10 +5826 29428 7 +26471 49671 13 +3161 47503 7 +53341 26367 5 +52223 6228 1 +21444 54799 8 +55465 21541 13 +21863 16460 8 +59483 14962 8 +43892 46709 9 +3217 28998 6 +42656 49227 17 +51070 16903 7 +21573 57540 7 +13385 5730 4 +34032 42100 7 +29581 39146 9 +57530 31902 11 +47268 37135 4 +43080 32916 12 +23670 27728 11 +41539 12610 9 +34608 1298 14 +48530 26963 13 +19130 19384 11 +16845 47593 11 +44372 21221 3 +54233 17318 8 +33891 50967 18 +27635 39383 13 +53107 22067 5 +30418 55076 13 +8406 46468 4 +10330 47301 8 +15686 47659 13 +16121 30276 5 +38318 26954 15 +8513 15366 9 +17753 41117 3 +28118 7749 11 +9911 445 15 +42043 45914 9 +49615 14791 15 +10257 7715 7 +33684 7016 10 +56455 31965 10 +17947 47088 5 +47608 51802 11 +53194 46506 4 +13250 58753 8 +46717 42956 11 +49922 25004 7 +46124 58327 7 +48635 12849 11 +14297 46522 8 +26247 32991 5 +56286 59163 16 +30049 18569 12 +11409 26368 5 +34065 36458 8 +27970 30521 15 +13666 25211 16 +1794 39233 9 +19612 25817 7 +55651 9668 2 +51163 58380 12 +58062 37530 4 +17952 14550 10 +18378 23092 16 +51476 1362 14 +14161 20587 3 +49030 46947 9 +13405 53860 15 +30805 52666 16 +21875 42671 6 +2358 36027 15 +30411 483 10 +37688 55717 12 +31409 55074 7 +11790 6190 7 +58969 34905 14 +40616 17385 11 +17012 8860 7 +52714 44777 9 +34874 4994 1 +28215 45166 14 +47315 20726 12 +5986 8366 15 +36342 26339 4 +23832 38114 11 +57444 42120 12 +17359 10070 16 +14284 35803 10 +44836 46564 11 +24443 39819 8 +57722 40429 5 +13430 7089 5 +16051 25529 4 +5870 7158 3 +54335 28493 13 +2714 31454 4 +42724 52908 14 +30191 6987 2 +59851 34061 15 +53972 89 6 +27370 42473 17 +7896 14854 6 +235 12407 4 +36587 17566 11 +39351 21165 18 +31426 35811 10 +26429 44694 5 +3459 45591 9 +38220 34046 13 +51243 47636 14 +14575 59144 5 +14151 4622 14 +16704 26378 12 +15797 53611 7 +35 38922 9 +51912 6865 10 +46594 185 13 +49196 27698 13 +45287 46440 8 +12210 38098 12 +2125 41571 9 +47235 37059 2 +53977 34584 12 +10597 21957 18 +29273 1072 12 +6263 24419 9 +35834 47400 8 +51182 46611 10 +42110 17321 9 +27182 188 9 +54720 34581 6 +39780 3352 9 +40396 10068 1 +42195 52095 7 +20411 58843 6 +40712 30242 15 +12544 58237 6 +10198 23550 14 +48161 17160 13 +13567 52976 9 +17563 28268 8 +59600 14491 5 +27903 51568 12 +41678 58002 4 +38453 44674 13 +34193 22851 14 +14822 40278 15 +8087 12371 2 +33070 40226 8 +20264 52528 16 +40675 31431 10 +58289 34447 10 +43727 22976 8 +51660 31360 4 +49407 16482 10 +22623 10935 15 +30868 5428 5 +8401 14929 8 +16234 4350 10 +18597 54102 7 +32738 56779 8 +56423 55179 4 +57294 46374 13 +1163 24444 4 +46373 2964 12 +46196 33981 10 +38613 8035 17 +50600 43484 2 +10133 56989 4 +47246 35381 5 +41212 42226 11 +41519 22871 13 +45958 28726 10 +21467 53758 11 +48192 17588 11 +27128 39094 17 +52040 54144 14 +24486 2661 9 +52753 28195 12 +2999 41318 5 +10977 53239 11 +23365 2564 12 +40229 10939 11 +29944 8 7 +32583 33257 4 +27260 37054 12 +44689 6825 7 +44860 55788 8 +7884 30684 6 +11368 47469 12 +1896 45202 10 +23187 5037 10 +684 43359 8 +11014 21117 6 +54889 32993 12 +12223 50752 11 +10279 52487 5 +41487 28584 5 +8594 33695 9 +48523 19985 0 +7692 19019 8 +38956 54463 16 +52610 3484 9 +26547 40062 9 +59989 52258 17 +29867 17286 8 +21774 48491 15 +51098 46212 6 +39900 36267 9 +41262 25857 7 +34963 55467 13 +42266 49690 17 +44852 3305 7 +41259 41016 5 +46557 44293 5 +8173 43386 11 +11734 1923 10 +902 17798 16 +1788 31005 13 +16605 34299 9 +15196 1928 10 +29304 28893 4 +20594 59455 18 +3193 5993 15 +22644 27986 8 +44557 15170 12 +38509 59965 3 +39985 4271 8 +23513 30028 9 +46012 30022 10 +25996 18343 6 +44969 59482 8 +3098 49125 13 +3686 56930 13 +18725 35178 4 +43096 915 13 +18533 2280 10 +52375 56877 12 +54420 34852 7 +8529 23149 8 +44707 11967 6 +666 5184 3 +24420 56657 12 +3876 53414 5 +49736 19944 12 +10037 17537 15 +18738 38231 9 +28069 48900 2 +17971 23844 6 +13256 22006 11 +22081 10231 16 +55504 32225 10 +13331 43102 5 +33832 1535 3 +56277 56272 12 +12391 46330 15 +18731 51138 16 +36323 47968 13 +38837 35490 5 +56473 42763 9 +29438 25626 0 +16926 8919 6 +43147 14502 18 +18878 48793 1 +52839 12586 10 +44779 23860 6 +3092 37382 4 +4844 48708 14 +59036 23703 2 +59881 53631 8 +7273 54083 6 +50444 35587 1 +50220 45975 6 +9672 2635 8 +47843 13450 4 +11648 54760 9 +1765 3664 12 +46199 11552 3 +23146 22395 7 +44477 16357 8 +14568 55807 17 +38053 21851 11 +29156 9858 10 +3814 59804 15 +26438 50350 1 +16449 302 8 +42677 12512 4 +22700 27712 1 +3142 9228 7 +57149 59358 8 +59398 24778 8 +52596 39829 9 +42157 27898 2 +40361 1534 12 +32775 7323 8 +24198 26093 4 +30380 13859 10 +8803 50417 10 +55978 52588 16 +46978 27769 8 +47519 42601 4 +10542 18420 4 +47494 2048 12 +19178 54323 18 +52985 25039 4 +8309 54883 5 +17777 36420 12 +54558 7529 16 +20025 52140 12 +51072 28306 13 +59240 50771 5 +36817 39403 5 +46097 45458 12 +839 30217 12 +37649 57097 10 +56885 18383 14 +1629 15338 8 +53163 21552 5 +7385 2908 8 +20800 50932 9 +55322 56890 10 +42128 49160 6 +1783 11622 9 +38818 55251 5 +32093 25723 13 +35791 16411 9 +46781 15055 6 +7173 2074 10 +53056 15533 5 +33466 49622 7 +11383 56889 16 +57384 8606 3 +10366 4747 9 +26646 9623 5 +1484 18925 13 +16541 15655 14 +7366 9829 7 +31504 47760 6 +53946 12230 6 +23372 25099 9 +36648 9205 13 +29699 24092 11 +4811 39050 9 +37071 47224 7 +49018 12359 9 +42982 56003 11 +5155 54981 6 +30983 31465 6 +21614 22462 1 +44100 25607 12 +52952 32942 13 +31740 35567 7 +31392 53918 6 +18708 29585 4 +13561 2805 15 +45428 30491 16 +8347 52690 9 +52672 5439 10 +29886 12884 17 +26365 32868 10 +10336 18454 11 +48378 50021 9 +17365 6212 2 +8102 57571 3 +1321 20517 3 +51272 28748 13 +42418 42866 9 +51969 28989 16 +5244 22121 6 +6543 15735 7 +37943 32570 8 +36355 44462 5 +17698 36059 14 +26322 54957 14 +31900 41435 10 +44829 3425 9 +7593 15529 12 +39997 4182 11 +57307 4396 9 +34175 27917 6 +27327 38304 7 +25321 10414 17 +3330 47992 9 +32100 5617 14 +9716 44545 10 +5162 9631 11 +2569 23684 11 +3508 12281 11 +4717 23934 4 +26931 2784 7 +26523 55224 17 +41296 12538 4 +22934 21458 11 +46648 10302 14 +15872 48398 9 +22499 17967 11 +48820 8441 10 +7839 46530 6 +12808 40460 6 +46722 49265 2 +42921 54841 12 +43297 20369 1 +32291 26809 10 +17775 31031 6 +28823 58835 10 +21452 8195 9 +12326 51567 5 +37346 4670 11 +44931 18863 10 +38433 30713 12 +2934 26376 10 +34309 24928 12 +36041 49059 7 +45870 34730 5 +30920 19450 3 +30953 25033 7 +7675 21495 12 +2249 34710 9 +20984 41974 12 +31339 50358 15 +25920 59879 6 +7788 30947 10 +7060 49312 4 +44580 19069 5 +35402 55640 7 +10509 55969 7 +15417 708 14 +502 15913 14 +37001 13118 15 +38110 29505 5 +47428 42584 6 +29325 38337 8 +2410 17393 9 +42719 12650 6 +37167 56110 4 +37515 42537 3 +46324 11372 11 +56388 55307 6 +31698 5631 11 +2765 23017 4 +59199 39457 1 +39681 16480 14 +54835 22822 5 +44220 16017 6 +31980 49737 1 +38366 36735 11 +4923 18284 6 +40738 9607 10 +38878 6367 8 +24406 13569 3 +29399 32311 15 +38333 16053 18 +416 15695 1 +25325 11970 9 +19631 38782 9 +19149 27679 11 +40428 39792 6 +50660 45850 11 +42390 19501 8 +22293 55892 3 +18972 51549 6 +59286 12539 9 +36112 51035 3 +42357 33289 12 +1271 35196 11 +8561 27605 15 +200 36219 9 +22847 25400 9 +35371 56683 8 +38978 43849 5 +27766 57102 13 +27031 4496 3 +28307 6478 10 +14885 40793 8 +54382 15051 15 +28035 29097 4 +31103 9082 15 +56912 15895 8 +23089 40700 9 +14019 58460 5 +54538 54014 12 +52257 2990 9 +51390 33807 3 +59219 32206 12 +25530 33002 5 +33175 16373 9 +1740 41894 10 +10149 10679 10 +52209 8480 5 +18960 8042 9 +57772 12065 15 +37005 9817 17 +52032 17884 3 +19312 43399 13 +54953 40150 3 +32035 59958 3 +58428 33368 6 +46183 40553 8 +11236 13046 7 +45524 48577 16 +26637 28031 8 +41466 15505 2 +53159 23035 15 +26487 28176 10 +30555 21832 6 +12657 14655 4 +32848 31749 17 +9837 55675 5 +348 11842 13 +56133 19090 10 +41367 22058 10 +9047 49431 3 +51633 37458 10 +32331 58816 16 +1549 55398 2 +8328 13803 14 +38620 37715 15 +7206 3647 8 +4652 35966 12 +19058 13277 3 +16323 25805 1 +10108 42338 11 +31073 24048 15 +10677 42569 8 +38384 50643 1 +19233 59955 7 +58970 7179 11 +11857 32393 6 +17580 33183 4 +49682 34310 7 +45560 22298 10 +18417 29591 14 +29181 31553 10 +59213 26846 16 +51266 10463 14 +20721 34580 2 +8699 41215 12 +9001 13247 16 +48546 26995 9 +20072 51546 3 +20544 55987 5 +44119 45153 10 +28227 48833 8 +43501 49155 12 +36227 13242 6 +14288 29429 11 +23672 12284 8 +39280 7994 12 +10548 15330 7 +57834 16032 7 +56932 11523 12 +6944 24228 9 +10737 35093 7 +42478 23318 9 +12922 12859 6 +35790 45308 16 +26028 11686 15 +51664 47777 7 +25179 12886 16 +34290 32032 8 +51421 28592 12 +18390 54218 10 +34345 35633 7 +57801 36794 4 +17931 6373 10 +25334 52174 5 +24145 19062 9 +52121 41291 5 +56065 16470 11 +50516 37711 6 +59725 40373 4 +20953 14529 3 +23338 34302 3 +57723 55588 7 +30893 33313 18 +46997 16407 5 +19219 38998 8 +26671 22943 6 +20329 50425 9 +34067 4545 11 +11858 29337 9 +22910 40030 4 +56643 14486 7 +14383 21901 9 +15449 43906 11 +58174 23659 12 +22911 26198 12 +5901 35758 11 +16151 9915 3 +22039 29172 16 +49342 39231 3 +55595 57626 11 +13795 26719 16 +39185 55049 3 +5027 15029 14 +3801 33904 5 +35227 2323 8 +22383 22397 8 +58665 10161 3 +36868 39590 6 +34422 15144 13 +40715 57941 11 +66 40862 12 +46876 50534 8 +32380 3041 10 +48704 55333 17 +32284 55683 11 +44333 12653 0 +29136 34318 9 +45325 36450 6 +8703 51120 1 +24996 7141 9 +47727 24743 14 +52458 36655 14 +40932 1212 7 +54731 19368 10 +20571 44968 17 +10667 33009 4 +1723 48003 8 +46903 33095 7 +54051 56306 10 +17513 41994 10 +40391 40482 10 +56813 10650 11 +54285 7033 10 +56052 20612 9 +58293 4313 17 +48981 13902 7 +34644 28260 12 +1554 21770 8 +1965 12465 9 +58594 44869 5 +24131 626 16 +39114 3806 5 +22320 22369 10 +22614 3880 6 +41319 11969 4 +47176 3913 17 +25162 52272 7 +11299 20336 10 +32290 58646 10 +15888 35586 2 +31084 45186 2 +2538 1117 6 +2026 5379 11 +18707 15093 3 +20786 18724 6 +3824 10255 8 +24285 2461 14 +35975 6128 9 +39121 28834 7 +43728 51598 0 +16180 43896 13 +7696 44175 8 +25338 35914 9 +6933 18763 4 +33575 7938 6 +34832 52775 11 +35434 41596 4 +58435 39862 8 +46984 48447 5 +35141 42800 11 +44314 7047 5 +34157 51529 3 +27938 51158 15 +9510 46442 10 +24083 27251 9 +39290 16289 5 +37004 54570 11 +51386 2408 9 +29542 26098 9 +12836 2114 6 +44788 53500 2 +35443 45195 5 +5429 45407 4 +7685 58102 0 +32490 19169 6 +4286 49365 8 +19587 229 2 +54693 6004 6 +16759 55044 3 +10369 14734 4 +14727 42702 8 +53426 4241 6 +40238 486 7 +17488 37812 3 +52929 28703 13 +47238 52696 2 +24306 38408 6 +59835 55823 14 +41689 53290 3 +14801 3700 12 +34736 54613 5 +43348 26128 10 +26914 53893 1 +31057 53282 12 +26419 34156 4 +31147 49364 13 +41743 25829 3 +51583 20002 14 +49893 42544 10 +56703 57850 15 +1630 43879 5 +1245 59639 5 +54609 12725 1 +46982 46244 13 +16803 7562 6 +17706 51755 7 +49417 17073 9 +56945 41815 6 +26279 16186 8 +18773 5758 9 +55346 8558 16 +48842 58871 13 +9825 17964 10 +39178 37481 10 +37806 38480 3 +48802 59302 15 +5240 14196 6 +12224 33696 13 +42154 9941 15 +42322 22235 10 +50234 3743 7 +13381 49486 4 +5557 541 12 +20784 1242 6 +36186 27753 11 +17219 41080 7 +3969 6279 3 +57200 23126 14 +4714 34516 9 +26744 19341 10 +2867 41413 13 +5403 11705 8 +3477 912 9 +20661 47978 7 +59468 34179 8 +53480 37809 4 +18822 27602 10 +17251 637 7 +28194 26859 9 +4059 1138 15 +9812 51975 4 +17143 39289 14 +19266 35717 3 +27434 4835 4 +56367 57093 9 +8693 50603 6 +37271 10175 7 +3892 9351 15 +48774 51964 13 +12874 51722 7 +37991 5236 5 +43171 1919 10 +22643 33399 6 +11256 28406 7 +36396 29526 8 +40764 36804 14 +23404 54917 8 +15679 41847 7 +21554 55086 8 +45633 58319 10 +44230 16497 11 +22203 6182 5 +13286 3939 6 +17577 48658 12 +49913 46186 9 +36000 38563 11 +14893 42858 12 +6996 53101 4 +55277 18300 2 +12328 47832 9 +27590 47439 8 +43281 9878 13 +1786 38807 9 +44599 13953 2 +1670 30189 6 +31768 53498 6 +12347 28752 8 +48377 28677 16 +8742 39846 3 +46639 8521 8 +59898 1022 7 +8573 7743 4 +5164 16018 7 +59605 23902 7 +19105 33528 11 +23436 35439 14 +17233 38474 14 +44534 7369 11 +8484 2690 14 +36762 55119 14 +24323 5874 14 +28805 23001 8 +55481 8853 2 +20144 55889 13 +36331 34085 3 +23097 22737 7 +6171 41778 11 +24360 39548 6 +29697 42716 2 +31237 19004 1 +44839 48649 14 +20158 49545 15 +41726 47218 14 +49471 25144 5 +17796 19555 7 +11703 29472 16 +47406 12089 3 +14235 37418 11 +34707 33905 13 +52116 45227 12 +42391 45368 9 +31149 45328 8 +26812 50819 5 +58431 12896 10 +54642 23939 3 +33392 42963 9 +5581 40040 4 +52279 54551 6 +31905 51596 8 +19139 56223 3 +32769 23846 6 +56790 1696 7 +39244 12480 13 +43460 22925 12 +11000 48972 10 +17598 53843 12 +29536 8619 17 +59041 15451 2 +17118 20933 10 +20566 54751 14 +7489 9978 4 +2056 4489 7 +18602 31371 15 +56061 51342 10 +6821 30751 9 +21645 29797 16 +12137 47820 5 +22565 11557 14 +9058 589 15 +43913 57655 8 +6894 20774 11 +11112 22323 7 +55385 47141 5 +10758 33810 12 +29956 20810 10 +38209 27978 5 +9728 4204 11 +9940 14351 8 +52008 45411 14 +20740 40399 8 +11733 58601 9 +22590 56636 12 +9982 35282 8 +22656 30913 8 +41879 11035 9 +32358 10837 9 +16819 37832 7 +13153 13613 11 +56785 49026 8 +49670 9827 12 +51795 19439 5 +43214 7602 10 +55575 10744 11 +55578 55906 10 +36418 24369 12 +21594 23103 5 +13475 57075 7 +34667 10148 8 +57355 40814 16 +40517 3981 5 +21551 32836 11 +16191 11549 8 +12203 45068 16 +19177 51414 16 +44587 6973 4 +40666 19603 17 +24707 7190 9 +22757 29660 9 +46383 7564 12 +45244 57605 11 +7606 51225 12 +2274 29010 18 +54284 1442 5 +30970 46030 11 +35955 48957 10 +26203 10847 11 +24573 48108 10 +4194 42846 6 +21688 15237 8 +45912 2126 10 +2030 48735 11 +37564 41377 10 +38598 19744 7 +51639 36462 7 +41449 8248 8 +43847 6971 6 +41565 3632 3 +39324 45605 13 +36124 21390 4 +14756 33806 10 +48841 25088 4 +31040 58759 9 +45492 14103 11 +49830 37449 17 +23967 49438 16 +18842 45237 10 +5692 12220 6 +35987 25859 16 +12264 12972 4 +17204 44468 9 +59178 5497 6 +23886 27908 10 +33231 19085 10 +47991 22294 1 +41175 26052 14 +15604 42217 4 +9690 9036 7 +6300 6167 12 +53508 37506 8 +4708 24025 8 +37633 33864 4 +41178 14231 16 +9699 4121 3 +38060 42836 10 +10995 32670 11 +54979 11041 1 +25085 13976 8 +21393 37907 8 +40448 19278 10 +54363 19034 10 +46726 22981 0 +16751 5921 9 +2339 46161 12 +24559 31583 9 +8078 58531 6 +16021 342 5 +10794 25071 12 +34333 56958 7 +30289 47450 12 +52507 55544 12 +22052 8377 14 +37397 36231 10 +33697 32598 7 +27127 4138 8 +10327 38717 6 +26779 55432 5 +43642 54845 5 +44244 39362 10 +40276 9638 4 +9024 11312 7 +28996 2028 9 +57816 9206 7 +10830 25839 3 +4424 36285 11 +46759 24809 5 +53978 3204 10 +59146 42789 8 +49410 26237 5 +18790 48653 5 +24586 24111 11 +24480 27969 1 +29627 3475 12 +686 780 8 +45827 56763 8 +47817 17716 6 +20750 47342 11 +53930 14708 7 +32747 24745 12 +44844 19691 1 +3500 46755 11 +805 46249 12 +12201 28051 15 +2956 40971 10 +36166 25606 3 +48353 27250 6 +13469 4355 9 +5912 25708 10 +52700 17869 8 +21232 37754 13 +785 9238 15 +25293 15802 6 +33952 57719 10 +45181 14266 11 +12817 35934 4 +30698 13532 14 +49547 7218 17 +758 36643 15 +17694 28092 13 +11137 27959 11 +54228 57898 11 +23988 59414 1 +53338 52446 10 +28686 20770 4 +12248 58340 13 +53907 30254 8 +21627 3043 10 +7984 16977 8 +26715 1283 8 +58442 37350 12 +38908 46433 8 +25299 37528 11 +16468 56895 8 +16150 41715 8 +27694 23926 4 +6219 29559 6 +41896 47390 9 +40593 28474 12 +49076 50759 6 +4935 46387 10 +42436 59802 12 +52050 24174 12 +19294 48525 6 +27446 56775 0 +49390 50966 5 +54738 32594 18 +32767 43416 18 +45764 26785 9 +51903 35649 6 +49138 16601 8 +51377 32741 2 +1904 42545 3 +20845 34651 10 +50142 53963 7 +41083 23654 13 +27307 29372 4 +56671 31660 8 +32695 16961 2 +58135 9213 10 +34365 59707 8 +55719 36104 10 +49904 10477 11 +25681 8926 7 +8201 18196 3 +52604 40505 11 +45649 28267 13 +38580 8490 5 +39617 18436 7 +53126 10371 13 +26132 16537 11 +8817 36973 15 +17043 40942 9 +41503 46055 16 +56419 7011 4 +50731 30313 8 +28648 18104 16 +2372 14595 7 +42187 31064 11 +39445 6372 4 +29191 5824 8 +53982 31430 0 +10154 7058 10 +50587 20234 8 +39944 4534 1 +18568 38911 4 +40746 59167 2 +16973 47003 16 +50608 14335 5 +31406 2679 9 +44351 34680 11 +25525 57494 7 +505 50210 10 +42947 35848 9 +45008 11396 8 +40652 32771 17 +21185 16217 6 +34127 18299 6 +58318 23761 9 +24112 7828 9 +20868 38874 3 +44879 31785 6 +40875 42124 17 +48305 27304 16 +49546 27598 6 +12970 27461 8 +4389 26989 3 +5277 17406 7 +39276 47357 12 +5177 25998 12 +13063 22810 17 +47524 41271 14 +20086 37912 12 +39855 3844 6 +31746 3871 7 +14958 35366 4 +30419 18616 16 +42427 6374 12 +31313 42355 11 +48142 10066 8 +28149 42497 18 +4618 35073 10 +27726 24094 10 +39007 6578 7 +32693 54565 7 +8449 44634 5 +2373 22921 7 +51193 5523 16 +47834 56823 6 +20327 25719 2 +39611 12471 15 +2530 51484 9 +48824 57056 11 +29690 52029 10 +31423 50231 15 +58865 42882 10 +14438 30885 11 +37072 5089 12 +58777 8047 16 +9174 6655 11 +3364 18324 6 +50837 3776 3 +49491 53062 11 +14955 14919 5 +42063 56284 8 +30186 42912 10 +52074 25532 13 +34153 6256 11 +39771 43113 10 +23056 35288 3 +54942 18997 3 +42794 55300 5 +24552 28983 5 +44513 42216 4 +7145 49747 13 +16805 9249 3 +33064 11517 11 +30878 9998 15 +4516 46643 11 +43049 56230 15 +31568 37761 7 +40513 52925 9 +46257 40605 5 +55085 14463 5 +24359 48939 13 +41746 17374 8 +25440 17827 14 +14719 1546 11 +11346 54616 5 +2357 26819 8 +54097 24923 8 +21438 42263 6 +47617 44877 13 +56227 47543 9 +44414 52022 5 +52090 53384 12 +42121 12548 10 +24088 8783 14 +5289 20667 11 +35999 19549 3 +45791 18457 8 +57189 1679 10 +48441 15639 4 +57314 17010 9 +5783 14504 17 +55731 9666 6 +31791 30961 8 +55923 55677 6 +38822 24049 11 +59857 46547 10 +44353 41480 16 +38369 29145 17 +48311 44772 10 +38750 16483 2 +23050 51668 14 +46942 31706 16 +55308 27383 11 +3795 25500 14 +36429 50372 11 +76 46995 6 +31559 21352 10 +55187 34145 7 +27076 42150 11 +6125 37288 9 +52283 28676 17 +1201 9298 4 +25044 13784 14 +18823 53063 9 +41323 9960 7 +59454 4583 4 +6315 49203 12 +30804 16147 18 +15525 18409 5 +41798 33897 7 +36594 32783 7 +12433 23793 6 +36922 26110 18 +17130 51715 9 +29951 4718 7 +50957 46119 11 +21976 26862 10 +35441 53169 15 +20397 32390 11 +12990 48947 3 +29132 4548 15 +1926 1597 1 +9865 18470 5 +4979 16671 6 +33126 24655 16 +20023 6889 10 +51649 47655 3 +53783 32986 8 +38705 24827 13 +10002 48489 12 +9318 8653 2 +36881 41391 9 +59393 4474 10 +54411 11979 3 +31542 15617 11 +46346 40725 9 +39463 33973 5 +10849 37010 4 +27592 10574 9 +57480 26820 5 +46856 50133 11 +13339 31017 5 +13023 29360 10 +43876 25148 10 +35724 54557 10 +33926 42401 5 +46152 11119 12 +19371 39933 11 +26702 21810 8 +21813 25682 6 +12984 33443 17 +54422 18590 4 +23970 53241 4 +38868 3045 2 +58924 20524 11 +40634 57437 10 +55186 5493 5 +41049 27087 14 +19812 42817 7 +55026 6615 8 +14930 25405 13 +35253 20548 8 +59103 40716 1 +10528 5734 6 +10966 58126 5 +18536 33766 14 +50557 11272 10 +34105 5655 4 +8950 15174 7 +22361 45130 6 +32808 10766 3 +48587 21938 6 +4494 34820 12 +43440 14178 12 +6189 26163 9 +47467 16728 8 +36633 45485 5 +40721 1238 5 +21775 7191 7 +57489 47285 9 +25212 51616 12 +40642 50456 11 +40178 1838 2 +52410 13147 8 +6270 40066 6 +38217 18856 13 +52564 25928 4 +29034 36752 8 +34501 43019 14 +43543 45887 15 +2559 37456 17 +40217 42096 8 +34713 46829 8 +59813 57380 15 +45084 53839 16 +52360 35700 1 +18443 7800 3 +52149 28162 13 +40967 32850 5 +20408 1588 11 +50205 44445 0 +28339 14406 14 +37598 30197 6 +13674 32713 10 +7999 19600 12 +49731 253 3 +31970 29919 9 +15692 16402 0 +51924 39990 10 +36042 28179 8 +43610 17896 4 +48839 5072 6 +23243 42630 9 +12015 59162 9 +21824 43146 16 +56693 35808 12 +16451 12236 10 +55070 29211 2 +879 53017 7 +25193 26073 6 +59065 47885 15 +45695 51472 9 +22122 59321 7 +51404 31975 3 +41628 6823 5 +35705 12616 12 +58885 29687 13 +11898 18650 7 +1590 20606 3 +32658 2725 7 +28059 39387 9 +54662 51181 13 +32005 49180 8 +32153 16972 9 +24662 10196 11 +27889 10121 8 +30384 35330 9 +20856 1047 9 +44027 22047 6 +57698 26370 8 +40562 17062 5 +49328 530 8 +42752 17956 0 +19076 2209 9 +12050 36688 16 +5474 52179 8 +40260 15725 9 +14709 81 5 +23683 34184 11 +39173 8475 4 +14308 24597 9 +47167 24258 4 +58012 26003 8 +28663 58469 17 +21646 2380 16 +31191 39428 17 +23048 12277 17 +23377 32948 13 +56290 32261 16 +57920 17339 5 +33164 53645 16 +29080 34304 9 +40416 39159 3 +26469 11760 7 +35822 37385 8 +19891 56375 6 +14724 59345 7 +8584 1009 16 +20108 11115 6 +19070 9184 4 +32633 7972 12 +6486 9558 10 +54413 5093 12 +26090 43497 8 +39600 56866 8 +22258 14035 14 +45517 33717 10 +15773 4302 8 +58803 39462 6 +46533 53269 6 +36679 25999 15 +52143 544 6 +53877 29295 12 +6253 14239 13 +33092 34899 8 +20978 52572 10 +751 25659 10 +33046 15294 9 +57242 41287 8 +2155 26906 17 +2651 38314 10 +24964 11593 16 +22253 54164 5 +56342 47765 14 +4553 31098 4 +11657 30614 1 +27916 3028 16 +51569 29311 2 +6837 18612 9 +54439 25126 14 +57324 15296 10 +55863 24354 10 +49849 32876 13 +22856 38207 3 +53151 27432 11 +17320 38460 9 +47185 330 12 +22135 12446 4 +15234 26867 7 +46955 38020 13 +4723 17613 9 +55210 32604 14 +13810 15608 8 +22555 54013 4 +44266 30127 0 +459 52871 6 +26054 16919 16 +6819 56087 9 +45594 1467 12 +40688 6598 9 +51096 49297 9 +9520 48846 7 +46716 50292 5 +18233 23252 9 +17879 35132 8 +59023 689 0 +3926 12992 1 +35670 47690 2 +31181 15369 10 +43566 30056 4 +2869 11083 8 +46768 43749 13 +2263 25939 5 +54947 40333 3 +31215 13350 13 +17226 17718 16 +44759 40461 10 +24718 23565 9 +17033 953 10 +29557 6329 7 +41396 49621 8 +42295 11876 11 +37953 30809 1 +41194 48016 12 +30203 18728 17 +54930 14796 12 +9907 38851 6 +23563 47802 6 +39259 51316 18 +31624 49794 14 +29412 11136 12 +3346 53537 9 +58309 32167 2 +59786 33442 0 +31071 55974 9 +15367 17013 17 +4125 18902 12 +9207 48905 10 +6490 25962 10 +17361 22205 13 +21621 7235 12 +46243 10021 17 +42588 23115 4 +30551 5603 14 +12360 54179 4 +49976 13421 9 +32607 15722 9 +19816 30297 3 +23802 4478 14 +57447 5668 13 +7890 4064 10 +11926 4710 10 +20908 22088 13 +52803 50712 11 +45261 50580 11 +56401 11669 18 +42426 14290 13 +59437 40335 6 +15247 11840 17 +27459 55124 12 +33890 4297 12 +55579 38175 7 +28920 10126 10 +50581 41270 11 +22678 3462 12 +1727 24386 5 +34434 6639 9 +14100 5335 13 +197 1246 10 +11877 29481 9 +19735 17440 8 +51258 864 14 +50626 36822 9 +45805 35864 11 +31123 39540 11 +45643 31413 11 +4228 40698 12 +35581 51428 7 +42510 34873 4 +26661 17763 10 +18542 42750 7 +18346 38367 13 +25603 44817 11 +10362 36960 10 +29518 19652 2 +18168 24047 10 +33364 56739 4 +38657 18971 9 +56672 57998 9 +82 20107 10 +6807 1643 15 +15851 17340 8 +26625 42589 8 +25404 18556 16 +18042 46952 0 +27179 16620 8 +22949 28521 1 +19052 22306 8 +37664 58794 11 +32526 56442 9 +36718 28383 11 +57930 46727 4 +43360 48411 3 +46596 59109 9 +15890 16484 0 +50048 53702 15 +47284 15833 12 +53073 20895 0 +17686 37375 11 +12144 43473 4 +49045 5533 11 +11118 8635 8 +37764 31670 15 +41105 58722 6 +10425 35111 2 +59834 34071 14 +58138 27801 13 +1279 26579 15 +32434 19242 11 +53641 43778 5 +52206 27040 10 +41250 59436 10 +14469 48559 12 +46093 17517 10 +25424 3911 10 +39745 39529 9 +56538 30341 7 +23625 45121 6 +29369 13387 14 +42074 55750 7 +30231 40083 12 +58957 36066 13 +26696 58044 3 +48849 7053 12 +33868 41444 5 +8058 40365 4 +56297 40070 10 +372 31703 7 +22063 33736 7 +17381 58952 0 +46703 12343 4 +38390 9284 8 +29695 53234 7 +28670 33173 7 +33215 51859 16 +19353 2621 5 +4233 59204 10 +20699 32571 8 +40861 38392 5 +19658 4301 13 +23729 13018 16 +21021 24488 13 +25135 31296 7 +10537 33140 2 +11592 22325 7 +39256 1613 6 +26981 2670 5 +54904 21532 10 +31512 39991 10 +15436 40342 14 +54515 41166 4 +16546 58049 5 +5505 52382 1 +21184 24987 8 +23214 58754 1 +48292 19451 8 +58111 25879 14 +54838 12584 2 +211 25351 7 +44091 57600 11 +57086 42890 11 +48876 1462 13 +17684 10906 11 +48923 23983 13 +28287 25982 13 +53541 55993 2 +41993 23232 12 +16061 15471 1 +12943 8879 11 +15918 15446 14 +46438 47006 6 +35917 20181 9 +19718 8211 11 +5153 33667 4 +42799 45347 4 +27149 54803 7 +23356 28943 12 +44160 2243 15 +27171 11391 2 +57991 57490 13 +16421 40299 13 +950 42066 13 +53870 51475 7 +8418 46565 8 +22815 33298 2 +34405 23686 9 +24127 41841 8 +7064 44086 10 +32208 43536 7 +51510 26910 9 +55339 10388 11 +50618 16802 10 +59118 52783 15 +37704 313 17 +27767 43953 13 +40496 17489 6 +51731 37944 8 +46527 7998 13 +21883 11667 7 +6583 41228 8 +36795 29896 7 +21418 41585 7 +57558 14063 2 +1985 36377 9 +15623 59623 12 +34691 17228 15 +44909 37283 15 +13678 30637 13 +21959 33919 8 +2883 36212 7 +40632 55020 10 +16867 17104 6 +45774 1762 7 +46640 38294 8 +6956 39626 13 +11866 45540 6 +15939 40660 11 +45659 21180 7 +47197 17809 7 +22641 19873 8 +8610 42372 6 +46110 48415 11 +39946 21179 8 +55950 45099 4 +5682 45417 6 +1044 4962 1 +31847 47177 13 +38241 31427 4 +21677 38273 13 +41576 19559 10 +43016 59784 1 +45433 39581 1 +55401 49349 11 +3287 21004 12 +34846 53862 5 +37752 23389 0 +19724 19521 5 +13926 21030 6 +41145 12408 11 +49181 23018 4 +37161 2140 12 +4243 27730 15 +2302 33715 14 +29305 55036 10 +52889 20319 3 +41532 49864 10 +30235 38116 11 +38155 8867 8 +44924 37563 6 +26080 42924 16 +41159 24429 4 +5193 37405 4 +50883 49002 9 +50396 47637 10 +13820 38305 3 +49306 40056 1 +14488 43547 5 +36613 26889 13 +30511 34077 4 +524 48040 1 +41926 42579 5 +15618 9094 8 +49008 9255 4 +59450 1594 3 +679 18647 6 +23259 19508 9 +29354 37455 6 +35851 35826 7 +13525 27494 6 +22684 14954 16 +12099 59273 14 +4592 29174 12 +25378 39049 5 +11291 46490 10 +32956 34404 16 +44325 16914 1 +42059 35310 14 +48006 27279 9 +47209 640 13 +34797 55639 14 +42218 2634 15 +35195 56177 9 +1694 20745 12 +41976 3422 9 +23859 22753 9 +35358 39821 16 +13357 40203 8 +30729 18295 3 +734 51580 10 +42996 32280 8 +15644 11354 9 +12505 46550 8 +41899 20219 10 +55990 43436 6 +25185 2483 2 +46938 42044 8 +35687 417 11 +31022 22199 7 +32662 28395 12 +5258 37556 9 +27298 28354 15 +5058 23225 4 +9364 54677 17 +18580 47918 17 +28712 40370 15 +11909 42533 17 +7090 7072 6 +29671 2478 8 +45949 50725 10 +57431 29773 8 +7799 3334 12 +21484 52653 14 +16950 38512 6 +2253 36968 1 +8295 4035 7 +15866 55486 11 +17256 35186 8 +14274 52633 11 +54225 57023 11 +42631 11012 8 +49956 57215 16 +34359 20161 1 +21735 1773 8 +53821 21939 12 +15753 42379 5 +44996 3082 9 +39584 54178 12 +47239 38665 8 +6683 26387 6 +52182 29590 4 +34974 23929 11 +11443 58755 8 +17961 14476 10 +254 2663 4 +19315 56019 17 +8600 23144 7 +54376 7556 7 +24416 51003 9 +19623 56604 8 +56352 17507 2 +51631 44418 2 +803 46187 10 +4724 41454 7 +44858 52390 13 +23136 50117 8 +45376 56554 11 +13335 17872 1 +30688 2254 12 +55387 49316 11 +12665 23830 6 +4561 34678 9 +26222 3120 4 +33024 2051 1 +43089 6422 7 +17868 217 8 +30696 1568 13 +510 4130 8 +35541 37700 11 +17590 14824 11 +50501 57525 1 +6198 36931 8 +45844 8985 8 +31730 26136 15 +35041 34 5 +30642 36857 9 +56607 16255 15 +31636 34709 7 +53104 49809 6 +45539 39437 1 +8889 31243 8 +4347 46521 6 +8864 37482 3 +15827 54498 17 +33363 47629 5 +5319 36139 7 +30470 16611 17 +21426 7455 9 +55875 6431 10 +50011 28882 4 +12046 17369 7 +45169 10774 8 +40209 24249 8 +9922 58530 7 +6730 47229 1 +20579 16447 8 +47565 53884 4 +11056 10363 7 +52855 29461 8 +20663 46998 14 +46635 32247 12 +57089 23298 9 +1627 50682 2 +54385 35731 14 +12983 13830 3 +43833 51477 10 +6975 45665 7 +49509 32369 12 +40137 24030 12 +52849 4175 8 +11641 4772 5 +48481 255 4 +58812 59462 10 +18766 11646 7 +54050 36798 15 +16436 42027 12 +29831 41241 13 +31694 44017 11 +41158 52865 0 +41595 55981 6 +58194 34699 4 +8929 56629 12 +30647 23317 11 +14248 43774 13 +4539 58661 4 +45642 24635 6 +38282 30785 15 +58263 4519 16 +53262 27418 11 +30399 25216 14 +12987 23818 2 +42108 46836 12 +13843 50374 8 +35118 12714 14 +40096 43370 6 +42607 9583 6 +13966 465 14 +40028 51949 10 +19379 17155 10 +55894 16403 7 +4323 30903 14 +52474 21072 14 +32127 16077 14 +24153 42233 13 +5911 20943 12 +48354 39342 4 +11544 17132 8 +38549 11799 7 +3949 41545 9 +58649 31731 7 +43920 46860 9 +17958 27774 18 +5338 54098 17 +45224 29960 10 +59672 10466 5 +11907 41738 16 +23814 33463 4 +50402 55735 13 +11937 13611 8 +1037 9422 4 +3762 22573 10 +49221 59073 6 +3411 5373 1 +19700 10084 6 +37231 30874 14 +42279 9241 9 +4307 59260 17 +29604 53535 8 +6201 44749 9 +18061 55956 9 +7645 47130 13 +51257 34993 9 +6949 9561 7 +26878 43830 12 +17276 43205 4 +50968 33631 8 +44686 5615 8 +905 37817 6 +51169 40858 4 +41712 56972 14 +54163 14449 12 +4034 16658 15 +41629 40321 5 +28618 41260 11 +31868 25082 3 +30432 30119 7 +28914 48440 9 +43529 44338 8 +43498 40152 8 +30033 31172 6 +4853 32934 10 +53561 12907 9 +39782 12117 4 +35619 53221 14 +12909 22893 9 +38711 20811 16 +623 27416 11 +45053 50303 13 +8221 23552 17 +7586 34357 12 +30452 18654 13 +38983 2522 10 +9892 3379 7 +44019 56665 4 +35200 43707 13 +32499 2270 6 +55634 35967 9 +12982 25217 9 +32535 57686 1 +25910 36307 8 +58402 36745 8 +3390 1456 8 +20826 51657 13 +10886 28637 6 +17677 51758 2 +1609 58996 10 +40980 42639 13 +39188 19820 11 +11065 39637 7 +35422 8745 12 +47317 33356 15 +40397 15984 12 +43559 30530 10 +1415 35626 10 +2755 2167 11 +22834 8243 10 +2326 41042 10 +41187 31576 7 +53346 32875 9 +3833 36665 8 +24395 12523 12 +49452 43132 5 +10887 6197 4 +13638 14199 12 +42596 48344 11 +10223 16401 8 +46130 56472 10 +52998 20092 12 +2434 49428 14 +59025 20547 12 +3386 51816 6 +29112 25849 13 +35685 56764 3 +10074 28357 3 +41723 23580 5 +19462 46423 15 +30946 42403 14 +14633 45472 6 +57885 59810 12 +19007 28837 10 +51606 9886 8 +31678 50681 14 +1792 31474 14 +29118 29308 13 +19035 44548 6 +12558 59772 11 +51309 11339 6 +42382 26373 12 +44270 37854 8 +7037 47336 4 +30919 36053 12 +14387 13086 9 +8070 17479 1 +23754 10645 0 +11965 32528 5 +17360 14813 6 +9040 23928 9 +10800 1213 10 +57938 22796 11 +52129 23153 10 +5637 21216 3 +21511 45688 11 +18917 58427 10 +11444 36215 9 +13704 50627 10 +26986 55888 2 +54220 20345 11 +36102 32337 11 +17138 32255 11 +50858 8143 11 +28324 53915 11 +22355 35522 7 +58876 40629 9 +23067 32356 9 +8276 11825 18 +42119 49206 8 +9965 6623 7 +31274 4805 5 +1493 48566 15 +59317 55236 3 +53333 43788 15 +38629 11049 8 +3845 43286 9 +7230 44985 15 +18706 21891 9 +14559 2672 8 +9398 1655 9 +7866 29882 10 +38330 50872 9 +43444 12751 8 +19460 1636 15 +44687 55992 18 +57487 32466 13 +55216 55985 9 +41414 48603 16 +46777 48964 13 +31267 34574 10 +17085 31836 3 +17853 36198 3 +55746 41711 9 +8320 13007 6 +20464 56986 5 +42329 4177 9 +12885 38994 8 +36033 52660 3 +27740 54414 8 +19640 18001 4 +14589 46149 5 +13875 1533 4 +28881 21104 11 +44876 35940 9 +37578 54154 12 +43836 44492 3 +52301 52010 14 +50569 26628 13 +28725 42909 3 +10646 36163 9 +35296 877 13 +31607 31015 8 +7458 51671 1 +1360 55716 10 +38301 42316 5 +41872 11161 15 +54171 50517 8 +56625 51902 4 +10916 12218 3 +57301 38894 4 +23417 13929 4 +18535 24565 9 +41437 13302 5 +33515 53564 11 +2625 12524 9 +24062 27939 13 +45348 26807 10 +43861 9467 15 +35860 25451 8 +19707 51703 13 +22527 31284 14 +53629 41762 14 +9071 18000 8 +49836 4826 18 +46920 30464 8 +2388 28804 9 +13967 58908 6 +11761 24303 10 +1798 46608 5 +132 36471 8 +26841 38892 9 +18578 24284 7 +23653 39682 8 +41085 15812 8 +52762 14923 10 +5922 39163 12 +3401 28338 13 +59848 23104 6 +15026 31206 9 +38670 28208 4 +52411 8342 3 +13410 49358 16 +41093 18203 8 +39242 10287 15 +45678 29499 9 +30749 52756 5 +21956 55805 5 +33900 47572 4 +43999 33608 9 +6024 18974 9 +6274 46172 9 +23537 48338 14 +58894 6799 11 +11373 46969 17 +49092 18628 13 +12820 4901 13 +12075 58410 7 +20696 15813 5 +25602 17326 10 +31988 6622 11 +12807 48593 8 +46329 11139 12 +45360 21619 9 +55319 9440 2 +18519 38639 11 +25413 25683 5 +57259 52464 12 +4082 42245 0 +34245 16897 15 +58243 25668 13 +34864 4776 2 +5691 54825 2 +37638 14379 9 +15308 15870 7 +47715 5195 10 +30636 3357 11 +45808 44116 14 +14597 55050 10 +44528 8644 8 +18369 31494 9 +3437 36282 13 +16292 51438 7 +28987 40264 17 +55066 50340 9 +25164 48011 11 +17387 6828 11 +23271 3497 15 +54768 32865 6 +25358 58270 11 +35798 23784 8 +36725 17039 8 +44604 6088 15 +25181 8997 2 +31863 52647 7 +52344 3289 9 +28636 55407 17 +9796 8400 5 +9958 52241 13 +7491 13047 7 +11194 40892 12 +12568 30564 1 +42299 39670 12 +23044 54131 5 +53505 19145 10 +14487 55738 12 +58850 50313 10 +38942 37116 9 +35267 24824 6 +36046 8741 10 +26828 39972 14 +27803 13892 4 +50843 36140 13 +4399 52104 12 +31753 16657 3 +50709 22702 7 +34604 57632 4 +7442 35339 12 +56236 24633 2 +34194 1880 10 +45170 25549 8 +3117 59683 9 +54194 53543 13 +27277 6097 9 +17120 23957 8 +32844 19436 12 +46038 1167 13 +29026 41698 15 +36432 30641 10 +51344 8868 13 +25891 11859 13 +38041 38239 7 +40126 11344 11 +5919 52059 6 +4139 47430 14 +53319 26508 0 +18745 12186 7 +15945 48845 4 +55740 55055 6 +56990 7883 9 +44977 36207 9 +46925 46428 12 +24698 36425 6 +37445 36131 10 +46445 26636 6 +25409 55806 3 +45548 42819 8 +26522 44269 3 +46131 35876 9 +21536 24120 6 +15659 18503 12 +15154 38386 9 +39043 49609 10 +46509 12999 14 +34095 52492 3 +5496 8359 15 +41476 6335 11 +8436 6833 11 +51900 50072 1 +48620 11485 15 +28540 37778 8 +38410 57479 10 +2503 17244 11 +13917 25783 8 +2401 12752 7 +20888 17891 5 +27692 38292 18 +42899 50352 6 +50188 23139 10 +32724 24922 9 +9007 2910 13 +34939 26251 12 +33965 1135 6 +20403 42152 16 +13442 18338 11 +21561 51249 5 +14673 41028 9 +45052 35710 6 +5154 18924 3 +36588 27313 8 +23215 44199 8 +14685 33519 9 +59807 50896 11 +57761 34821 6 +21443 16681 11 +8616 51726 9 +22785 39229 10 +6670 24706 6 +4253 1294 16 +152 6124 3 +54315 17975 10 +1041 27479 15 +43696 11055 10 +7689 31322 5 +8510 21582 12 +14582 14250 17 +43613 27665 1 +48380 59388 13 +45833 19338 3 +21814 5135 6 +44614 1221 9 +19602 58827 10 +51186 55012 6 +3993 31334 14 +471 38080 11 +53762 26218 9 +19911 21075 11 +49013 36093 3 +27139 6276 10 +38009 5971 7 +34270 842 9 +29465 19073 16 +18641 36266 2 +5809 57278 3 +26039 10516 15 +47844 25475 13 +42847 59766 10 +6888 40722 8 +22516 24795 6 +8053 54833 1 +1861 7622 3 +9406 57793 5 +43998 20167 10 +48539 24050 8 +9955 6184 11 +18172 15359 9 +8799 40024 7 +51977 40251 6 +3110 55636 13 +56836 57460 2 +55550 41401 3 +50141 47822 3 +59363 29975 9 +25582 49631 13 +15996 57388 7 +36335 50328 2 +712 11162 0 +26238 17072 2 +930 13608 17 +27186 15486 5 +19546 48630 15 +59217 18341 8 +22049 33387 11 +32585 4810 6 +37725 9521 9 +10829 2436 4 +27567 39399 7 +23662 36659 4 +56307 29906 10 +15123 57729 11 +3518 55594 8 +36148 262 11 +9867 35163 5 +31889 42595 16 +47162 23375 10 +12793 18218 4 +44187 16125 12 +18232 17304 0 +55518 22086 16 +14349 31052 8 +13942 7965 8 +5618 45989 3 +13962 33914 0 +41379 34197 7 +12543 55114 13 +22922 34781 6 +16776 56502 17 +6305 49436 11 +24346 46996 5 +36326 33222 7 +29750 5010 0 +6930 40497 8 +52372 41463 17 +41735 10315 13 +6816 10187 16 +45628 38581 11 +4813 19719 6 +56312 20766 9 +16023 37022 11 +14505 1347 14 +44802 56852 10 +52071 29977 12 +4198 33751 12 +36563 45746 15 +36245 31417 14 +30133 9888 9 +8574 49212 8 +14283 44891 4 +50508 34595 3 +47917 29209 6 +20819 2347 15 +26293 49490 9 +19068 28664 9 +37513 57755 3 +9876 59129 17 +1155 37286 2 +29718 27856 3 +21853 20425 7 +44857 24133 2 +6669 8093 4 +56233 53667 8 +8725 35559 9 +46613 50698 13 +54730 50079 12 +15079 54771 15 +8307 42804 8 +50641 40212 7 +564 24867 7 +26331 15860 14 +43729 51252 10 +10464 36995 3 +58914 18110 11 +7239 23740 10 +52023 20912 3 +7076 8386 16 +22692 54491 14 +12611 22577 12 +4088 48862 5 +53831 22204 12 +26045 44127 9 +52727 26760 12 +56310 31107 14 +35557 58367 10 +24755 56179 6 +48118 13210 8 +56207 35937 10 +3304 31416 6 +14707 19741 10 +53124 25352 1 +33446 910 7 +6714 5955 5 +7405 18836 8 +51296 17715 8 +1308 30319 13 +22710 50582 1 +6034 8360 3 +48355 50064 10 +4111 39741 5 +31925 26374 10 +2536 45819 5 +30561 35732 11 +40751 53512 8 +42768 56820 4 +34553 41456 4 +22995 11265 12 +43378 58444 14 +21701 20189 14 +35036 57467 16 +18067 25919 5 +52463 50384 16 +32706 22591 17 +24453 32805 14 +15430 6877 9 +46065 24152 11 +17071 41327 10 +8772 35770 3 +8247 8761 8 +16827 39255 13 +21925 23682 17 +41306 55856 18 +6240 21686 17 +23506 29015 6 +11221 34325 8 +21474 17756 9 +17895 18267 8 +9034 20717 4 +49954 24417 3 +28986 14794 8 +59913 28820 5 +50007 15645 11 +43656 38964 15 +52438 5822 4 +52817 16376 1 +38602 28459 9 +1275 2527 9 +31509 13008 4 +52362 12864 3 +1111 13198 7 +6323 26516 10 +40577 5666 6 +39729 57765 10 +1425 50828 1 +26451 40518 10 +57952 33581 12 +49042 14341 10 +517 40743 11 +6074 55326 11 +45585 57351 11 +38119 55932 11 +20505 18414 17 +34266 1426 13 +28835 29333 7 +42824 14242 14 +30757 50022 5 +36541 49940 12 +4332 34018 10 +6027 37077 14 +29073 35995 4 +34035 48418 8 +32681 50439 16 +4864 38800 5 +19698 2511 14 +3460 27953 12 +25027 26427 1 +44681 30212 3 +2391 57840 11 +40099 47651 3 +46318 54925 16 +12190 56477 12 +15721 45852 9 +50152 46358 9 +15880 15502 13 +37222 13367 10 +43950 15977 10 +29493 27470 10 +22626 25650 7 +52393 57395 0 +52569 27160 4 +47939 8565 5 +8501 21175 15 +16626 20243 6 +49767 14067 13 +52185 39551 4 +22034 44013 8 +16910 59561 12 +54029 20178 4 +14364 1981 12 +33376 39555 6 +53855 43034 16 +26675 47849 12 +14926 47311 10 +21908 31979 6 +51489 48596 11 +39884 34475 5 +59979 58966 4 +26873 10451 10 +33155 26583 17 +55235 37112 13 +23330 1701 2 +49039 15838 10 +45579 3469 8 +45451 504 6 +27626 58878 12 +53114 31292 13 +39028 47889 5 +18298 14016 6 +42364 756 16 +49753 58621 8 +20021 30372 3 +56497 55963 5 +13012 24563 10 +5046 38371 10 +7426 22667 11 +51973 36525 8 +50180 15494 15 +25985 41261 13 +59249 4794 7 +58087 15262 4 +32042 30570 5 +57343 35599 6 +24017 14611 11 +57305 47720 4 +10844 7203 0 +6775 19184 8 +3944 58918 14 +46229 48890 10 +23669 22053 13 +59359 31126 10 +57178 29576 15 +10104 3564 6 +14761 19987 10 +34006 47212 11 +12390 56525 15 +35037 41380 12 +7055 29732 0 +43256 17919 11 +24785 42102 7 +9981 24097 6 +4761 59013 16 +31549 9659 10 +6443 38835 1 +38129 53106 9 +40646 20824 9 +54426 39971 15 +58159 49565 18 +45588 85 9 +42790 33993 12 +24293 54222 10 +26303 49310 7 +50719 35207 11 +23251 49361 13 +6767 34346 10 +4705 24953 16 +30553 51994 10 +7960 14670 7 +43597 22329 7 +43269 13814 8 +27059 26897 11 +17006 17242 8 +50436 42857 13 +23660 25690 1 +19534 38326 9 +56446 24255 11 +21512 37630 5 +10760 9061 12 +43181 40398 16 +31876 46272 15 +49058 17064 7 +44290 3240 5 +29477 6301 9 +53547 19710 9 +54485 2381 8 +12632 54607 2 +27625 35374 12 +1914 30625 8 +42888 21610 4 +14547 29278 10 +49584 6239 13 +23123 27045 13 +14842 52877 15 +55874 46725 4 +28207 52234 8 +19800 35775 7 +31254 55756 10 +40831 49041 3 +59480 50974 3 +12415 42300 5 +11310 244 10 +30402 15877 12 +21553 7236 7 +29816 50541 4 +59521 18882 6 +2539 8492 9 +24849 29367 6 +7732 54464 2 +47412 34471 5 +45479 7697 13 +12546 26053 6 +43852 195 11 +3482 43521 17 +20939 35988 9 +28335 5463 10 +48948 41348 9 +54869 45736 7 +31865 52543 3 +8525 52502 15 +8081 6759 8 +18949 52977 14 +59084 40528 18 +20574 51878 12 +32144 30690 2 +52332 18387 14 +42462 48198 5 +14823 21025 9 +43985 45122 13 +59598 1139 9 +55408 5282 9 +36324 49270 8 +41584 23122 11 +52198 23101 9 +34086 20526 2 +34376 41632 11 +44053 53439 8 +29036 1166 16 +43516 10473 10 +647 40224 8 +9053 6517 9 +43992 30535 10 +34107 3849 8 +1986 10857 15 +1440 9026 8 +19996 40633 5 +8689 10112 10 +30728 40878 8 +32851 10541 5 +23770 46174 9 +34518 32779 9 +28056 25406 3 +19770 13831 3 +120 48745 6 +8027 40170 12 +19087 20660 10 +44022 11888 9 +45723 28718 2 +26864 19970 10 +52834 54159 7 +21300 47214 15 +57866 19401 11 +28269 2604 3 +3782 21923 8 +56460 8334 2 +51373 28500 7 +24802 36623 9 +10063 28180 14 +27541 4020 10 +38263 2792 3 +44382 5838 9 +10512 48554 6 +18447 54907 12 +24797 199 9 +53453 17701 7 +37620 43593 8 +38600 11834 9 +39512 21905 2 +57224 40214 11 +33023 50016 1 +1869 46973 15 +40647 52497 16 +27921 38622 9 +26871 45090 9 +47388 18117 3 +54009 18174 5 +5941 19863 6 +58281 4681 9 +45434 12339 0 +24282 27587 6 +33834 23096 11 +37387 30414 14 +58171 36465 8 +44215 54460 8 +12368 34021 14 +33860 37850 14 +51499 38873 0 +56593 28707 11 +7598 50704 10 +41461 33867 14 +37333 4324 17 +36150 31937 7 +12830 38655 9 +27893 10753 8 +9522 58671 14 +26857 56926 7 +59046 46289 3 +45264 50224 10 +4120 10320 5 +36903 53261 13 +24790 6857 2 +21020 37580 11 +27436 59776 9 +31828 4948 14 +34213 49872 0 +28028 56851 5 +40118 19632 9 +33318 15674 12 +23177 42632 2 +57962 37801 6 +30931 25448 3 +46418 41857 5 +5491 21899 4 +9031 32663 5 +25819 51301 8 +33218 37248 8 +42495 20672 9 +25252 47373 1 +17885 10194 3 +46663 50191 10 +17140 21461 11 +46574 2135 10 +27670 12565 11 +34459 45456 14 +59825 12129 5 +39601 2671 9 +44756 55517 14 +27906 39919 9 +29062 52668 2 +57348 53952 16 +27472 10636 6 +28492 38102 4 +3576 713 5 +52535 56935 14 +30488 30087 5 +19158 11956 5 +11711 17423 3 +35379 32001 8 +31391 54709 9 +35449 44024 8 +48119 51365 1 +29802 30440 15 +34796 761 9 +40909 6577 10 +58844 34969 16 +16158 6457 16 +58577 2853 10 +51996 59682 14 +36057 50814 5 +53609 40933 7 +5849 53485 14 +47591 14118 7 +53660 45038 12 +49398 24534 12 +48645 14210 4 +53323 27613 10 +31007 17272 7 +45992 40941 13 +55852 18003 10 +55953 14891 12 +7583 40927 11 +15191 43496 7 +8160 32756 2 +9103 44563 6 +16128 21787 17 +3055 23769 17 +10319 58561 9 +10225 45741 4 +31620 1651 9 +45441 4964 10 +58892 21718 12 +29833 19258 7 +48987 48237 14 +3945 9296 4 +33249 40149 17 +32177 10042 12 +1172 57950 8 +20438 58846 6 +41970 33020 5 +27585 40337 4 +10142 9064 14 +17255 48791 3 +32750 6350 8 +52554 56355 2 +11769 54938 11 +49382 4176 12 +668 28596 5 +7029 33248 6 +54208 59180 8 +39113 32777 16 +15631 34378 12 +46855 30048 4 +47410 11147 6 +44824 39391 17 +49964 21132 1 +46349 21008 13 +54975 17158 9 +19275 8066 17 +7263 56725 8 +29682 43128 7 +40783 44874 15 +42761 4969 10 +54995 33081 12 +48239 50854 15 +47310 15555 2 +9359 4682 8 +27754 50487 4 +10689 39003 7 +21210 6917 5 +34687 33301 11 +5930 500 4 +17165 23841 9 +38424 27930 4 +17575 11363 9 +2115 10048 8 +30461 21695 6 +58881 7328 11 +18147 2455 9 +28345 6307 7 +15609 51566 10 +20450 11729 9 +40080 42775 10 +34409 42626 9 +46729 59932 4 +15875 54329 7 +56056 35127 17 +47341 16490 14 +35471 8552 10 +13145 57171 8 +16202 6015 7 +36526 39694 18 +41335 16201 11 +20033 58800 8 +20467 5778 11 +31263 4589 9 +2931 25878 7 +49724 533 9 +29753 40488 16 +40948 39501 11 +12996 16900 8 +25298 50360 16 +24631 54828 6 +5574 47267 8 +46865 38139 1 +47283 4336 12 +15377 12618 7 +34630 40829 3 +904 30537 16 +54418 6774 9 +30840 30083 8 +34648 20681 6 +4532 18049 3 +24723 57247 10 +26969 16420 14 +37257 22743 11 +16435 44561 4 +41106 10781 8 +5934 57079 14 +58854 39243 9 +16987 31483 2 +25772 49889 4 +590 6091 11 +52486 25596 8 +36476 12132 1 +45304 26413 14 +34740 16927 6 +38491 19629 15 +44792 54081 10 +6966 23045 4 +36771 40859 9 +804 20007 6 +42534 19949 10 +47163 25702 9 +44004 33936 4 +30172 54396 15 +45597 23798 10 +6132 37113 7 +191 25186 13 +47050 39910 6 +22528 18050 8 +29563 14390 12 +34868 14146 14 +30909 5550 6 +632 4696 8 +43285 55520 13 +9754 9270 16 +42563 35176 9 +30720 37789 6 +15993 12379 8 +49589 11239 11 +41492 3413 3 +17040 32650 5 +48077 12229 14 +22956 27148 1 +42645 5398 9 +23826 34148 7 +44425 3189 9 +49725 26743 11 +6469 9430 5 +40701 37654 16 +50151 35509 2 +30099 59602 16 +23534 28616 13 +22701 20432 4 +55648 38778 17 +58369 20377 12 +59328 5055 11 +26962 33733 11 +4874 33400 7 +17606 45860 4 +54573 30195 6 +15850 4527 3 +22449 26783 9 +54305 13341 10 +51326 5713 9 +53517 8132 16 +56637 45036 6 +5789 15201 4 +27017 56614 10 +25686 56022 14 +34449 22414 6 +48872 53200 10 +11631 6698 6 +20339 575 16 +18476 28199 8 +6513 41809 6 +10741 53232 8 +46156 24263 16 +25785 44884 10 +55087 38680 13 +5370 43989 4 +27828 59441 10 +39988 21293 8 +8299 17923 8 +8323 39543 4 +25243 36530 7 +7919 53790 6 +17139 18123 8 +8378 8546 14 +28730 19091 8 +48798 209 3 +19153 59884 15 +31305 47154 12 +26105 35484 12 +59637 18838 12 +48281 23837 7 +16548 53240 15 +41626 46706 13 +35891 38434 11 +21316 34896 12 +27775 46007 6 +37911 20921 8 +44213 58379 7 +40177 46940 11 +4895 58060 11 +9749 6610 13 +47640 17744 11 +18425 16503 3 +2658 19425 10 +33487 18428 7 +45298 42616 12 +43105 12952 3 +789 20743 11 +32135 13311 9 +30695 43029 4 +4802 35131 10 +23309 27187 8 +58343 54501 4 +46994 16893 14 +20157 12064 12 +36790 21201 5 +38218 41021 12 +8847 17623 15 +35121 20886 7 +54500 24482 14 +48179 56224 8 +54168 18929 7 +22417 20994 8 +36534 21379 8 +28573 27099 9 +58593 50496 10 +27947 33830 15 +31842 27255 14 +6060 42781 6 +12629 800 18 +44598 43758 3 +50531 39898 4 +39680 21641 11 +16057 56521 9 +6688 8663 10 +32915 12926 5 +54167 11545 10 +30314 43695 14 +48544 8446 10 +46584 35547 16 +30021 31372 9 +18720 13551 12 +11762 2099 18 +11976 50250 11 +42521 19569 8 +8976 22030 8 +41535 16249 10 +33032 29651 7 +38257 8987 8 +54704 29451 4 +54846 46941 13 +9486 53669 8 +17526 45340 6 +57413 55809 13 +35181 4172 10 +5735 30660 13 +39704 47148 12 +17875 25710 9 +32707 34474 10 +27046 28283 15 +27113 25329 4 +18321 19854 3 +37422 19218 9 +45753 43167 14 +48794 3549 4 +25249 18939 5 +40487 2355 10 +23223 9461 10 +30896 4003 6 +51304 20795 14 +55879 3619 8 +32151 35720 0 +9367 20223 12 +704 41361 15 +53866 47488 7 +16409 41945 14 +5792 54664 5 +29271 53796 9 +50721 35487 8 +48100 18365 11 +55394 19585 10 +38745 49512 9 +48619 30980 12 +6749 9879 8 +43895 26129 8 +54992 28308 13 +54902 47367 8 +52708 59606 5 +38313 11534 12 +17867 46247 9 +58758 20379 7 +56544 10726 16 +52097 33633 4 +18131 41324 16 +7783 39385 13 +40543 13186 14 +7284 15329 7 +40992 26738 8 +2485 48249 9 +51456 52510 15 +30556 31329 9 +42388 20592 16 +49282 45055 4 +48978 39219 11 +18797 37118 12 +24792 12839 5 +50525 8855 1 +51284 2826 9 +59551 8139 12 +627 1096 10 +23151 26189 11 +23673 54149 13 +26827 41608 4 +6963 49383 15 +5998 41648 10 +7479 47716 8 +32527 7778 10 +33740 36504 10 +44016 10651 16 +11624 37201 5 +46754 15691 12 +38694 41398 8 +3529 3629 6 +33910 29389 12 +46005 42861 5 +4924 50023 2 +15335 33411 7 +11522 30448 6 +2271 14493 16 +53570 24068 8 +35070 59655 11 +46961 23737 17 +13713 54399 7 +45710 14064 12 +12942 49483 9 +50201 37836 8 +8969 53166 9 +9581 35317 8 +40378 16029 10 +29643 53707 7 +16682 13120 10 +7380 6704 7 +8060 10747 9 +21402 37913 4 +34757 50390 1 +35006 2589 5 +42949 29017 4 +19102 18813 10 +18746 42983 14 +55826 38071 12 +790 23787 7 +2623 18734 8 +20646 50959 12 +9571 40339 15 +10853 16581 15 +54601 2650 16 +45143 12965 16 +53617 12420 12 +50424 25625 9 +31641 41282 4 +54445 17816 7 +25840 10217 13 +35515 4101 8 +51307 24 9 +41897 45897 6 +44046 59057 9 +7252 2978 15 +55022 39337 14 +29770 8332 3 +13037 26221 10 +8805 34511 7 +21486 16386 11 +44334 16331 6 +26774 30914 9 +55253 38349 7 +38363 36902 11 +41161 48838 12 +7 19164 10 +11106 35738 7 +34103 20391 9 +18132 32606 2 +44438 27397 18 +45495 37532 3 +37472 22096 9 +138 6635 11 +6063 36352 9 +42740 30544 6 +23191 19202 9 +28853 30934 12 +52118 52440 4 +18057 56933 18 +43586 59451 10 +3633 30539 15 +48692 51518 12 +52038 53469 3 +54585 14592 12 +21162 48963 9 +28023 16890 14 +49892 45563 8 +37476 50900 14 +55328 21032 13 +42602 3314 4 +26011 29047 6 +21518 26912 13 +15818 15746 16 +59767 2078 9 +16869 33829 7 +27813 41127 10 +50753 10028 11 +23679 18828 9 +2420 3639 8 +13694 33790 8 +6173 27809 11 +4777 38685 10 +33160 40643 9 +45359 37244 3 +12788 45693 5 +50764 47656 13 +7130 34025 0 +2512 5467 10 +37936 24401 10 +44052 50589 5 +1905 4990 15 +24588 23148 15 +38995 55509 12 +20729 9565 12 +45931 15817 9 +577 48827 6 +48515 58155 8 +12173 20775 14 +43640 30118 13 +41724 12312 7 +42273 46523 5 +10856 50776 14 +35197 40323 8 +45252 45671 13 +58990 15209 15 +44212 50408 16 +50179 25870 16 +57167 54685 5 +44937 9328 9 +45677 30122 3 +29809 30107 2 +20599 53395 5 +43438 43458 4 +6209 41411 4 +43752 28652 10 +10100 38194 7 +36143 26740 2 +39917 55882 14 +42336 17830 9 +51950 44564 10 +40328 12730 16 +7546 13002 14 +6288 47098 13 +13995 22468 9 +51065 27669 13 +55530 263 15 +32872 42929 4 +42088 32348 8 +5238 15008 6 +57856 10266 4 +58212 59543 8 +10192 1334 7 +46270 15334 14 +25989 38162 1 +9154 40480 11 +54076 54186 16 +56748 49238 13 +34181 10153 6 +3742 44035 12 +386 29638 12 +10169 48865 6 +53650 6557 7 +37069 50339 9 +2104 29501 4 +42341 33628 3 +29721 54860 13 +57831 51261 6 +19823 58804 16 +46764 30250 15 +19319 9534 11 +58657 30686 17 +40061 19975 11 +41143 45400 6 +1872 43878 5 +5185 30501 16 +54859 25420 3 +49122 24716 8 +49368 10496 8 +44375 28980 13 +48154 55534 17 +56093 29089 11 +4250 5411 12 +42082 23295 4 +24277 56014 11 +40106 56677 14 +59996 34881 10 +5275 38084 6 +35841 27052 10 +56305 15909 10 +54580 26270 4 +1032 38457 14 +46214 28368 11 +10393 49668 8 +38605 57044 7 +59985 49552 6 +8068 57721 11 +20897 11636 4 +50379 56927 3 +9371 53654 6 +52915 23757 8 +23079 46417 3 +26761 43208 3 +45732 53276 12 +55519 18676 13 +1924 40974 4 +11017 36756 7 +6509 5331 10 +24533 35115 12 +3665 21826 16 +25797 31489 12 +5924 9339 14 +20772 48352 4 +44076 9721 2 +7522 17342 15 +13310 42939 9 +29280 3582 10 +33931 57251 14 +8900 47434 6 +21281 8667 7 +4913 47790 2 +8390 58267 4 +34920 1769 9 +12737 13851 16 +34517 27414 9 +23516 33472 14 +23066 15930 8 +27115 31602 6 +58624 54120 15 +43345 25230 3 +37214 45151 5 +24065 4351 9 +35191 22404 12 +49284 43551 10 +15339 45001 4 +4413 10031 8 +37566 6068 8 +40239 26083 9 +852 37720 14 +35630 55554 7 +2217 54864 5 +21308 38860 1 +22018 8024 9 +58836 24370 15 +19613 48097 10 +3579 18209 12 +15541 8814 15 +37811 48983 12 +57309 49141 14 +11947 48861 16 +53327 8989 5 +33460 17676 11 +35198 25202 3 +41128 18721 15 +9215 11702 1 +33035 38574 6 +6679 26079 17 +13928 12467 7 +52110 25675 12 +25941 18887 11 +16067 53457 12 +9239 53764 15 +2007 5687 10 +4370 10398 16 +24355 14839 6 +40387 22485 16 +22786 37218 10 +58458 20032 7 +54985 55448 7 +1774 20809 6 +34355 42867 0 +28369 14690 10 +33504 8936 10 +37235 18903 12 +6222 14040 4 +21231 14821 9 +54593 32988 15 +9905 29140 13 +11492 40284 5 +33492 59320 6 +46805 42095 7 +18430 33924 7 +30333 35202 7 +1624 1123 3 +41904 59987 5 +23196 46815 7 +8551 8440 12 +17695 28509 5 +2023 1911 7 +24924 55665 4 +54773 42885 3 +59491 31522 8 +15960 6151 11 +23376 58198 9 +41543 33855 12 +4736 43035 9 +41996 48677 8 +25209 42309 5 +5801 8318 9 +42904 26606 12 +32867 23465 6 +56918 27878 8 +24012 1755 4 +38968 10244 6 +30027 3952 8 +7989 49473 6 +13667 16078 5 +39014 279 10 +21981 36125 15 +34371 52991 9 +52914 52712 14 +43815 45342 4 +37606 48194 9 +54394 37970 8 +28048 47511 12 +29276 6621 12 +23643 38471 6 +8977 41577 8 +33146 30059 7 +35172 8234 13 +19231 20173 9 +17018 54176 11 +20429 14852 6 +22356 32195 9 +12428 30446 16 +37726 48562 12 +44148 18748 7 +21420 39181 6 +321 21909 3 +12271 15138 7 +33314 27825 10 +59094 10807 5 +54983 55276 10 +20909 22411 9 +41557 11347 6 +2655 40147 6 +4568 31070 11 +15001 37767 5 +46399 484 9 +40711 4400 8 +18028 52801 2 +7285 5359 7 +29077 22845 10 +8631 56099 3 +30136 3828 7 +48041 5451 7 +33858 27601 14 +42145 34949 11 +12353 29319 16 +19469 59453 11 +59636 24523 14 +58717 57582 13 +1876 20416 6 +44231 19940 4 +23013 33056 6 +28101 46237 8 +27143 9155 11 +9594 11893 12 +23553 35251 16 +9441 44457 3 +56814 48405 11 +13712 32637 8 +11661 15554 7 +19104 15749 8 +33947 56955 1 +4906 27437 4 +17480 31734 7 +30325 19286 12 +10022 50651 8 +13045 18142 10 +3657 13486 10 +4002 53490 7 +19468 23238 3 +35868 50341 11 +14427 46142 2 +24341 28693 4 +27509 54079 2 +24558 56654 11 +17135 18302 7 +1470 38660 3 +1506 54393 7 +39882 24140 15 +41054 23156 10 +19711 25198 13 +13692 31019 10 +167 39909 12 +43667 43856 14 +1735 57401 5 +29071 33724 8 +15741 24175 10 +17309 24410 14 +2845 23755 9 +29969 566 12 +25275 38728 15 +10991 25428 7 +48459 42796 9 +50087 20640 11 +34623 44809 6 +10702 17434 9 +20124 35231 9 +19990 2465 9 +11022 41295 9 +44238 23973 7 +54854 39297 3 +46904 37310 14 +31250 52224 3 +31831 45338 9 +49874 26266 11 +19606 51054 5 +3074 35180 7 +40857 4902 18 +31693 3914 16 +17900 46021 10 +33438 57410 3 +5108 11758 0 +52096 9694 11 +31594 50480 7 +2160 43351 2 +55306 26590 6 +58585 44753 7 +21357 12681 2 +28430 39492 9 +18853 30608 7 +10941 10292 11 +53962 50949 7 +41481 43822 14 +26002 37345 7 +29621 12799 0 +51769 51399 10 +29084 56263 11 +22498 3859 12 +47880 20410 10 +58525 5390 12 +24095 38543 3 +30819 12687 10 +21967 32774 14 +57587 45453 8 +10553 57862 10 +50355 40281 9 +58895 30599 11 +6859 57257 9 +23779 20615 6 +20593 27378 6 +20724 47643 3 +20487 25401 4 +13324 32722 13 +51031 12903 15 +18592 14621 8 +34935 35357 8 +11532 22278 2 +21441 12973 6 +47702 48033 7 +22077 28991 14 +50859 6712 14 +17034 40402 10 +15856 52537 8 +56536 14703 12 +41410 2012 7 +4638 21124 8 +43965 52298 3 +39582 30542 6 +2773 34944 6 +38324 19429 13 +18265 20816 7 +17382 57236 15 +31640 28136 9 +37440 20436 4 +33723 54703 0 +3600 13117 8 +17702 47613 16 +14166 29490 3 +50795 50960 10 +4922 3523 9 +46332 54643 7 +16297 15677 7 +13699 37349 14 +47683 49808 13 +31986 2574 16 +31954 43402 11 +10171 8707 9 +38814 19119 7 +57030 32795 9 +34130 148 11 +43552 23418 8 +54881 16902 6 +46314 38886 6 +21715 54105 3 +41315 13300 5 +7305 52242 2 +41639 9734 4 +18872 17001 14 +47785 16984 8 +18816 44393 9 +56050 11465 9 +1438 27136 3 +12675 8427 7 +58663 36401 7 +59525 33547 7 +6647 28427 1 +22447 28732 14 +31208 19214 14 +28362 57912 7 +18247 26463 3 +34151 35236 9 +39474 20590 5 +41874 40582 6 +33787 36985 10 +59263 13079 11 +35167 55547 5 +59337 7277 7 +23426 52619 9 +57337 6870 8 +43223 33955 13 +20323 28969 7 +20443 3441 1 +515 23771 11 +48461 24345 1 +21271 18179 1 +10275 43127 11 +13284 31063 7 +41124 29143 9 +1016 20963 9 +7132 13548 7 +11716 56146 11 +37517 7865 8 +47208 51217 8 +45696 35065 12 +11985 48266 7 +38161 17203 4 +56198 6102 9 +8722 15822 12 +29611 10214 5 +39705 44315 9 +34485 51503 12 +46609 47858 14 +19476 27957 7 +38356 3869 8 +5757 20702 9 +48103 16279 8 +32427 40792 8 +37148 1637 11 +16387 3439 8 +43439 48148 11 +34571 29214 5 +22484 4471 11 +15603 46786 6 +45484 52568 9 +44584 12153 7 +52348 866 6 +54188 47907 8 +52228 25016 8 +17549 7615 2 +25214 25072 8 +13080 7166 5 +16600 11197 7 +7627 3446 17 +7212 34912 14 +31374 38951 8 +12631 57397 5 +30890 6700 4 +20867 14444 7 +58393 12500 7 +54836 52347 5 +1097 19113 12 +16132 29440 16 +43257 58973 2 +19134 47776 7 +5871 59045 5 +37066 39139 14 +18314 18140 7 +9934 46705 1 +18680 35601 15 +23776 47769 7 +45999 26385 9 +40026 22817 16 +4314 33105 7 +47078 46842 1 +46175 53098 9 +42779 20757 10 +4571 8233 7 +17178 46116 10 +31109 27850 6 +33720 24746 6 +45520 42766 12 +20954 36357 11 +14300 29235 6 +48736 17638 8 +48312 43974 10 +19221 3769 14 +6628 41132 10 +55747 40302 10 +29674 7432 4 +39889 48488 9 +17153 1608 9 +44990 10433 8 +43268 14381 10 +23540 31488 10 +13271 7002 8 +50147 28440 13 +59794 45234 13 +29578 19230 3 +3651 13531 6 +8993 7018 2 +55855 33196 8 +55453 34453 10 +2014 4021 15 +35802 32190 9 +38444 31382 13 +7353 457 4 +32869 5343 8 +29941 35274 9 +2425 50657 14 +36382 4995 8 +14265 30808 15 +1207 20829 9 +9267 23675 9 +6842 44684 12 +38093 28777 9 +41045 30204 14 +42604 32656 8 +22964 44087 11 +20402 43064 12 +11357 35421 15 +18841 51372 3 +17217 43991 8 +22807 33822 11 +261 25552 9 +44261 11010 12 +46677 30029 12 +40650 1013 14 +15087 6568 8 +17170 46922 12 +35888 32111 12 +55188 28854 7 +42950 21275 7 +15616 7133 13 +55764 21751 9 +499 18637 12 +24605 15324 6 +9437 38650 16 +20995 48302 7 +47679 42648 16 +59744 27032 9 +54229 48325 3 +42820 24107 13 +27848 6737 9 +58824 11865 7 +5746 58922 15 +29378 40748 5 +20647 22941 13 +53826 23314 14 +31946 2159 6 +23591 48131 9 +3169 44637 16 +36081 44463 8 +58229 7294 6 +16464 25481 11 +5694 40263 1 +20417 56387 15 +9619 8828 13 +2592 50574 10 +26649 55438 10 +15054 45512 10 +23364 40635 3 +3570 57006 17 +1678 21397 5 +35842 12192 11 +25994 57465 9 +39005 20001 17 +54145 19293 8 +27357 57943 13 +5435 51821 13 +13740 34331 10 +36882 48940 9 +48650 13931 4 +57821 3672 7 +21556 21294 14 +3315 51406 10 +15041 14108 7 +27727 46140 9 +34190 6465 5 +26171 2814 10 +41337 53559 7 +46749 31354 6 +31333 17548 10 +22878 2069 6 +7730 8062 12 +38707 9162 8 +47699 17639 7 +7415 53527 6 +37873 8973 13 +13948 17445 14 +53944 55933 9 +26149 48710 7 +8113 24612 2 +49798 3156 11 +13702 53774 14 +14236 26703 12 +12452 53883 10 +6761 54528 9 +56698 6352 9 +51425 15073 6 +48779 5442 7 +25166 29110 9 +52854 1432 4 +2707 57934 7 +21730 34343 14 +22745 52811 9 +29137 44374 11 +19853 22041 13 +50628 9402 0 +8823 30607 2 +56960 23428 9 +14227 40176 7 +45322 18134 15 +50135 3139 12 +26426 3451 15 +37692 844 5 +47353 38106 9 +4629 20102 8 +42851 13467 9 +23075 8413 8 +28906 474 6 +53779 53399 7 +50068 21254 3 +58925 821 8 +29825 56328 2 +8788 44435 3 +12295 35199 15 +30649 55381 3 +59755 6858 3 +50926 44297 12 +10564 53681 8 +51323 22545 3 +49137 4433 7 +56175 37831 8 +46388 31452 7 +16131 48748 8 +39248 28542 11 +23555 1162 14 +43928 59752 10 +34654 2938 7 +6393 59573 15 +17934 44719 12 +11176 56829 17 +11198 39592 7 +10717 46345 11 +5073 15714 7 +51917 31681 2 +14088 20992 9 +47774 54579 7 +46572 56650 16 +28489 45316 4 +48990 56078 13 +36853 42733 9 +55936 17907 7 +49055 43803 8 +21324 57128 7 +56585 54476 6 +27744 5970 4 +50067 42624 11 +25444 1789 14 +33755 50342 16 +6827 39618 6 +2188 17127 4 +408 40316 5 +42941 23326 12 +27762 15414 17 +1131 39554 2 +32492 30025 11 +4484 19310 10 +21866 31458 7 +36764 2652 3 +17442 41256 5 +17008 50710 15 +41938 13890 12 +20844 7711 9 +56393 24687 13 +17589 59774 13 +5660 53330 4 +57936 12257 11 +39304 48024 5 +58615 7477 16 +40220 25511 8 +28112 17955 9 +49210 7835 1 +45358 14787 11 +10964 835 5 +56633 3227 10 +6249 23405 10 +58078 53110 15 +57736 5697 8 +58915 39450 16 +37746 5284 6 +17682 28484 10 +1516 22884 7 +6019 2088 12 +5175 25693 11 +57022 32568 1 +24818 46809 8 +55722 34835 12 +51351 19754 10 +56754 7396 6 +8544 33759 10 +21488 20145 8 +7045 17494 9 +20286 10259 6 +43676 53292 10 +5575 420 12 +52515 115 8 +34628 50119 15 +32889 6582 14 +16985 37504 6 +59662 22637 5 +52635 59961 12 +58326 37018 14 +52268 29523 5 +11089 55645 15 +57694 59024 11 +6079 58315 4 +55185 14579 15 +48622 38226 8 +9455 46462 7 +17349 220 2 +35927 43518 8 +22127 59160 14 +53167 30318 11 +9532 8669 18 +47733 2781 15 +12150 1898 6 +24607 9910 5 +35475 43120 18 +52329 12409 10 +18109 26501 8 +26317 53005 7 +51265 46732 6 +54195 34119 11 +16283 27150 4 +34253 21998 5 +2585 59266 3 +58009 11289 13 +4890 3797 5 +10203 8294 0 +21274 49883 2 +22136 16691 9 +51325 20238 4 +34794 45107 14 +21113 50550 7 +43295 26716 10 +29291 52947 9 +202 37948 9 +58526 18588 10 +27295 26087 10 +46309 24637 10 +14532 33405 14 +16414 2451 7 +10426 22225 8 +15581 55927 4 +7794 59862 7 +36793 34458 18 +718 36277 4 +52455 16014 4 +22209 16800 7 +8760 37780 1 +18027 13988 14 +22984 39330 9 +28271 22997 9 +25484 10376 5 +49828 10813 12 +23108 51984 7 +1531 18696 7 +43513 38230 11 +37922 9280 13 +41920 925 15 +10684 45832 3 +2214 20294 10 +56128 46838 8 +25029 41687 4 +10351 6158 12 +757 30306 8 +58207 31167 7 +53501 28378 8 +20491 9569 10 +20220 35169 9 +14188 7462 4 +10350 34188 7 +56824 32373 9 +29223 17298 13 +23142 28641 8 +47227 44471 9 +49678 36239 4 +20074 40810 11 +7464 9967 10 +47729 34837 8 +3400 55382 9 +12749 41827 13 +48032 45123 15 +45644 6356 4 +52442 30051 4 +22265 39657 9 +7568 994 14 +7767 28109 7 +27804 4495 8 +52133 4387 1 +37377 37323 0 +16872 26089 2 +20290 46751 9 +46153 55232 8 +23989 54863 16 +3054 16130 3 +50326 9742 1 +11071 28944 2 +47928 46278 8 +11854 17723 16 +59988 38400 13 +15168 45507 11 +15894 33059 17 +33087 49476 5 +49139 37132 9 +29432 37110 8 +30038 13706 11 +47195 48036 12 +1483 59368 6 +47094 14386 11 +11823 59728 9 +59962 55378 11 +19283 14892 8 +10448 47293 5 +59624 14363 5 +35224 57032 12 +26678 30405 8 +42481 2504 12 +38719 5250 7 +25290 39071 8 +27426 43211 4 +30016 54388 5 +17236 52315 9 +53592 57837 14 +51374 24627 4 +14698 28075 4 +28154 21122 8 +15732 5444 9 +35459 7632 4 +4658 53602 7 +7049 44709 9 +57784 26005 9 +5515 41197 7 +54003 7423 7 +51692 2594 6 +29397 58906 13 +31786 58611 11 +27019 14345 7 +46489 15394 9 +23835 44412 3 +22297 43935 2 +54364 10016 9 +57628 15498 11 +37061 32600 6 +9097 39726 9 +41741 45268 4 +33127 54977 7 +45835 497 14 +30006 9144 10 +32141 6671 10 +8228 1979 7 +43737 28666 9 +44232 50258 12 +2439 40863 6 +47307 47731 9 +57039 51355 15 +7327 50766 9 +43601 32375 12 +31500 735 12 +20261 26538 13 +3159 12634 4 +34677 53003 14 +34602 29212 12 +12035 26670 9 +35812 31068 11 +32263 40451 9 +8073 18526 11 +31961 57173 12 +29630 32298 6 +50035 35850 10 +11781 34408 5 +29293 41383 5 +33679 45803 5 +26548 41375 12 +22853 13358 17 +55004 10329 7 +24328 48803 10 +31668 36719 11 +14569 31291 9 +12014 56616 11 +26172 46435 13 +32733 46185 9 +37874 55871 10 +58566 33713 14 +5088 9372 12 +49251 23024 7 +55812 28187 5 +2944 39452 3 +25580 31852 7 +11109 19889 10 +59173 4221 14 +46785 26341 2 +35209 20206 7 +11093 3485 7 +12388 28140 3 +51426 50204 10 +12640 37981 6 +28428 30515 3 +53662 58875 5 +49624 26847 10 +37525 43036 14 +27672 52151 11 +51327 14966 4 +4430 15044 7 +50054 28793 9 +22568 13401 10 +58109 47146 12 +359 50593 9 +16812 36484 2 +14872 14436 17 +53571 49758 9 +2926 32555 12 +46477 43118 10 +38626 21776 9 +35505 10575 8 +29484 14069 9 +46467 14859 5 +50915 16381 4 +57392 23903 13 +12757 29041 8 +24969 18818 10 +3144 4916 17 +58129 26938 15 +715 55779 10 +11208 11801 14 +55083 7774 10 +11301 37561 10 +33622 38270 9 +34650 34286 10 +3921 33242 11 +25208 29684 3 +6438 21611 13 +50041 43511 17 +31745 47178 12 +15147 54861 11 +39122 8756 6 +45253 52580 5 +50460 11671 6 +57808 43289 7 +17142 49381 11 +12601 35831 8 +9115 29170 16 +21523 45486 2 +43659 14083 9 +20235 2150 17 +30098 13905 15 +20008 21129 7 +40962 51787 5 +35315 39826 9 +55120 11461 15 +25904 22993 14 +31361 21470 2 +45399 14792 11 +42310 44995 11 +50956 56658 6 +39079 14269 2 +29595 17546 13 +58774 39419 11 +57575 51032 9 +51577 37258 11 +58609 41686 4 +52434 1332 13 +28795 45599 5 +26826 45129 7 +37290 50165 7 +31999 41933 10 +37172 16486 10 +58534 363 10 +5092 59919 4 +10280 13093 8 +27137 23209 5 +52795 43889 12 +21463 19001 12 +29124 21934 15 +49462 55754 15 +38974 49185 1 +31059 28560 2 +45669 12159 6 +15221 2933 13 +40672 51641 10 +41992 49960 14 +55915 59614 11 +56343 11814 10 +52509 4911 5 +50856 44617 12 +36236 37823 10 +41133 11230 10 +16580 40832 11 +39024 16752 12 +57143 18555 12 +27639 4473 5 +45383 55490 4 +33011 5961 4 +21015 27607 14 +36444 36017 10 +2181 50366 9 +32044 33319 4 +36280 53497 9 +26043 43770 9 +27442 5669 15 +58642 14743 12 +18013 57104 3 +43843 35326 13 +27779 49970 15 +8200 29075 7 +46614 19438 11 +8076 40964 11 +35501 43908 14 +33507 12875 5 +6248 14145 14 +4363 32904 16 +12673 15940 7 +42704 45859 16 +45290 50870 7 +49598 25823 2 +55822 50542 0 +35110 1436 5 +49028 24914 11 +34352 52091 8 +17519 51524 5 +37994 50975 10 +41700 39923 12 +9909 9323 11 +45228 27415 12 +5915 11238 6 +47260 59626 13 +40020 36518 7 +10050 31502 7 +7445 23084 16 +20229 56009 9 +44595 31319 14 +43885 10484 8 +25354 29738 10 +26629 39677 9 +9211 23014 6 +59135 3754 12 +33943 8911 7 +25595 58951 9 +52030 47143 11 +32745 10603 11 +35936 41772 5 +874 55273 9 +8130 9005 7 +55282 33730 10 +36806 44095 9 +47966 58928 4 +38647 8455 12 +12745 52520 2 +46962 31330 7 +59780 9471 6 +13408 55154 6 +51838 2230 7 +10993 26263 4 +50786 22629 5 +36974 13888 16 +38422 12119 7 +28159 38401 6 +4687 12357 2 +55430 46291 9 +5017 48227 9 +402 30047 5 +33137 149 8 +53582 33997 12 +24750 20609 6 +15039 17437 11 +45179 19020 12 +50373 46016 16 +9828 56628 14 +2310 13128 4 +3456 29556 2 +30108 4300 5 +59873 8422 7 +53859 9897 7 +41469 10814 7 +34336 11460 10 +42227 25110 7 +40409 30115 8 +54633 39098 8 +37546 50784 13 +27673 5651 9 +11533 32964 4 +12040 15341 9 +4342 41345 10 +42887 47048 11 +28739 33349 13 +7129 55196 6 +1691 13204 13 +58744 24027 12 +45828 42407 14 +58764 41214 10 +27561 27823 14 +28010 46937 11 +1871 20306 12 +4877 54987 6 +31966 27943 7 +2192 53572 5 +15300 47561 7 +3556 50129 14 +7639 50579 12 +22326 6032 10 +42593 9389 13 +13868 56568 10 +5695 15035 12 +29284 29647 7 +14777 31074 16 +28011 44721 16 +24106 43712 5 +19017 59423 12 +40484 55865 11 +10089 52665 11 +52575 30089 2 +16504 22022 10 +2920 39408 3 +5837 11276 15 +23588 35573 14 +33354 37433 2 +22075 17846 7 +35712 16854 9 +48992 46290 12 +6506 58252 11 +28249 5968 13 +32678 50235 2 +50977 24934 8 +16771 39376 7 +45188 33795 10 +59420 4633 4 +54690 12181 5 +58059 54922 9 +42277 47626 0 +1107 6773 2 +5086 38062 3 +43842 25479 6 +8618 59349 13 +56129 53998 9 +45466 43503 12 +14702 47241 2 +55516 48394 12 +12158 11971 3 +35821 9976 4 +27745 5736 8 +2027 39033 8 +52924 35562 6 +26174 28626 4 +49187 4704 12 +30200 55491 9 +44915 37028 15 +5245 51962 5 +28161 18418 10 +2416 42668 13 +28317 53569 8 +24832 49415 13 +10792 14331 15 +47714 5382 5 +33823 39349 3 +19395 32617 17 +9708 47330 13 +32320 308 8 +43733 29827 9 +39794 36930 11 +38971 16319 15 +8893 58220 11 +35939 1479 8 +37217 16348 7 +21473 41588 6 +16552 46524 14 +36975 53088 2 +39441 22673 3 +48786 15208 4 +18677 4642 9 +15343 48511 8 +9304 44611 11 +35413 43802 11 +39072 17366 6 +39634 7906 11 +52491 43709 9 +34026 44192 6 +31006 53369 13 +32657 42923 12 +39768 46778 12 +37602 59477 7 +35050 13765 4 +5272 6119 6 +5303 5224 14 +5252 29364 3 +24278 43055 8 +15672 55015 14 +40434 15832 14 +19284 27981 13 +43825 41799 10 +47117 41581 9 +5480 56447 10 +14223 27361 12 +42420 57095 7 +11196 27238 12 +47959 7281 8 +42905 39683 6 +43969 27771 16 +48581 34079 11 +40059 569 9 +13771 17484 8 +42684 3107 4 +18271 7318 6 +12485 57474 7 +6411 33753 8 +27500 21743 9 +32900 728 10 +55051 20291 9 +46240 13762 3 +435 33151 8 +49419 54369 9 +6107 8296 5 +9167 45950 13 +46674 47018 9 +35513 5402 13 +54189 43538 13 +28978 24103 6 +28825 43730 6 +24128 35058 8 +59771 896 13 +1454 55868 8 +11028 26040 8 +39423 15531 16 +34496 6480 11 +28952 9020 13 +1721 59559 6 +50452 25855 5 +11076 34900 15 +13171 40027 10 +28164 8755 8 +28313 15731 11 +6925 24598 9 +59560 46013 13 +11340 31955 6 +30557 39089 13 +32859 50780 7 +6808 23743 17 +40437 56831 9 +36496 6389 11 +18292 45674 10 +40336 58480 7 +46090 40032 5 +34411 39211 10 +19424 43346 14 +26013 53983 9 +8708 14759 4 +49626 52236 15 +27888 43187 9 +51947 22027 5 +16310 19894 6 +12381 17491 8 +18098 59076 6 +53566 52707 10 +13779 12232 5 +52341 41740 12 +11002 9234 11 +20736 21341 9 +1090 37673 7 +45916 31410 4 +59459 14820 5 +55790 37156 12 +18294 23385 9 +53879 56347 2 +14059 40668 7 +23813 25515 9 +56070 29202 15 +17690 14501 8 +51051 10878 2 +21987 13202 12 +53350 48149 8 +16081 46758 8 +54478 72 8 +47653 17629 6 +46543 4481 10 +19107 29298 11 +23792 36459 14 +34609 58433 11 +33269 49581 11 +24596 25008 17 +4491 26586 12 +37989 8916 3 +59377 28381 13 +48479 50239 9 +53263 43548 12 +12306 21724 13 +27530 19208 12 +15049 34473 14 +15899 7287 16 +28346 21050 16 +26925 58737 2 +31177 7661 8 +59016 9626 7 +4584 22868 4 +50873 38723 15 +36498 25940 8 +50345 25344 7 +55761 58472 10 +2856 48030 13 +5352 49226 16 +1864 49174 12 +11243 18210 4 +35018 24411 14 +16810 2803 5 +160 20817 9 +23581 35921 11 +42347 1376 15 +8275 3553 3 +48765 21007 4 +23483 41443 3 +35060 18150 8 +5466 826 15 +4636 25815 10 +26640 323 15 +25764 19002 7 +54391 6976 8 +20834 29914 11 +992 48358 8 +19094 44282 4 +11585 31298 12 +54696 27677 8 +45296 39137 10 +50246 43145 16 +4657 47129 2 +1527 56217 1 +32569 30447 10 +11329 54821 15 +11571 12194 10 +536 59617 13 +59787 8238 10 +5087 17558 13 +17949 34503 11 +28961 16539 9 +12795 59656 13 +5443 2010 3 +30475 11921 4 +7688 33629 8 +13526 3962 10 +9869 21521 0 +43087 16804 16 +30907 142 7 +28716 25720 8 +11929 36799 10 +21065 58563 10 +8256 39420 9 +31051 4778 10 +754 15413 13 +25001 40350 9 +13833 48727 0 +49519 16008 10 +15392 40809 10 +232 7429 1 +48751 31519 6 +5121 38817 11 +34529 54037 13 +5641 23307 4 +39051 16209 3 +1236 4381 16 +38997 39010 11 +39358 43638 12 +49136 21803 14 +31862 57316 9 +4427 11995 3 +32134 16922 8 +8452 10657 3 +4956 4227 10 +10917 7371 6 +51395 59478 1 +41467 13076 1 +39135 54059 9 +45367 58919 6 +51680 11582 9 +20855 10389 9 +38643 43202 13 +39547 10035 13 +22352 47888 8 +27194 59555 9 +55930 43413 10 +36302 25389 7 +5646 25876 1 +36039 54651 3 +33854 43891 12 +51721 46432 8 +11816 57448 11 +59170 51106 8 +19609 12940 10 +33476 9929 14 +13081 24405 1 +49000 598 10 +37436 13074 8 +55418 58934 4 +1850 6474 15 +52080 54470 13 +25545 42352 15 +48374 36813 7 +15538 54809 6 +44482 39854 1 +56597 57083 16 +31953 46381 10 +37453 49231 7 +42182 10904 6 +42094 26633 13 +53622 23239 7 +32814 19890 3 +18750 4236 3 +1730 18690 15 +6137 50161 4 +11011 57424 6 +39775 39994 8 +53991 11385 15 +48856 58710 7 +47081 7443 10 +10842 57420 1 +4141 28366 9 +23561 48299 2 +15255 47122 9 +18489 22690 8 +18713 59845 9 +12131 33394 10 +39544 17980 13 +42638 37770 11 +20759 32960 10 +25447 41779 8 +55521 26000 4 +7359 32391 12 +12399 2945 6 +38910 48432 16 +50749 59392 4 +50343 9101 6 +18194 16075 9 +37370 9843 13 +52064 46819 7 +19305 1621 9 +50947 5530 10 +24768 20973 16 +57027 42832 8 +20907 32950 4 +10285 31923 10 +5820 51291 11 +1017 16276 6 +7378 54024 5 +9223 41191 7 +24665 3136 8 +24497 39827 17 +53786 2481 11 +55264 15944 17 +56218 57254 13 +7683 15027 13 +55206 16502 7 +4393 59796 8 +52814 2175 17 +57007 20437 5 +46010 32112 4 +38042 26491 8 +4619 20874 6 +26814 8064 11 +48825 46513 10 +3478 19960 7 +59089 51435 7 +38452 51055 14 +29004 29764 6 +15479 54994 10 +46675 21097 5 +40905 18687 8 +47280 27070 3 +43415 26484 9 +47670 5677 3 +46512 54765 3 +40512 11133 7 +335 7313 7 +51530 55576 2 +1885 18330 10 +33711 31769 4 +15991 56176 9 +44821 13595 11 +25711 3540 6 +6559 35806 6 +48702 39133 10 +46696 39858 6 +53148 5663 13 +46833 7342 8 +25255 59535 7 +11846 20298 1 +16050 45505 3 +2529 45026 11 +27491 857 9 +6120 53419 7 +57040 5113 5 +50359 15127 14 +57615 3343 9 +51854 41818 9 +19128 40240 8 +49057 38556 10 +37429 6230 7 +50061 26575 7 +27637 32453 8 +9496 56531 11 +50442 58861 8 +49723 31384 2 +25245 17823 7 +52452 2734 8 +30939 59445 6 +38760 19986 15 +16690 26369 2 +44838 17472 1 +20763 39756 17 +2176 52968 12 +58202 18582 11 +20695 20861 11 +51889 58613 4 +40584 14928 18 +49429 34812 6 +54858 2419 4 +56188 57502 9 +56171 28417 13 +3344 9989 3 +3380 37120 3 +40961 28429 13 +20017 48054 11 +28696 31499 12 +28734 18705 4 +19005 29616 13 +15141 7757 13 +4712 54080 6 +45923 35307 16 +36850 18212 5 +48886 24941 10 +40001 43053 8 +26418 52106 11 +15052 50349 12 +28821 10118 1 +40559 35155 10 +26838 2572 8 +59369 21966 9 +34565 15058 12 +37250 30675 6 +40849 23150 10 +59503 13491 8 +58299 12892 15 +47286 29349 16 +23921 24390 3 +8129 37824 9 +48086 32367 7 +59905 8795 7 +43886 25313 11 +13893 1389 15 +52887 31346 6 +35564 58623 12 +23925 57349 5 +29824 13343 17 +14546 24507 13 +42503 6067 11 +31067 32704 5 +53954 56948 12 +42035 19240 9 +54929 14127 15 +34502 38583 4 +27356 19273 3 +23688 42453 14 +25828 52184 18 +38840 2618 8 +20382 16179 10 +2343 27956 12 +38481 6820 14 +20768 59411 9 +19685 13721 9 +17518 52428 0 +59195 59604 12 +4614 10825 7 +57909 45288 3 +8196 14382 15 +48760 36672 14 +19919 56153 8 +19412 52818 12 +58149 54119 12 +56561 33067 10 +28431 39063 7 +26691 11472 8 +57034 34991 4 +31089 31506 11 +24642 45784 13 +6763 11100 6 +51646 7475 10 +57813 34160 8 +12244 55017 6 +33594 56036 8 +50821 14477 16 +46412 37181 5 +45424 14965 4 +12255 35755 17 +51146 53926 6 +50880 45905 6 +13003 37601 3 +58726 47184 7 +29050 57535 9 +22609 36710 14 +25466 47752 5 +51952 327 4 +46720 40462 8 +35677 14456 12 +50576 18589 6 +8032 29976 2 +42033 49937 8 +25838 48883 8 +58193 8959 12 +22419 8913 8 +3706 28526 14 +1354 22674 4 +5332 3513 11 +43189 28211 12 +30208 1918 15 +3207 59829 15 +21345 54638 13 +193 6328 8 +44155 11450 12 +3358 34564 10 +21811 5128 2 +10163 16019 9 +36658 34783 11 +26620 51820 4 +32917 56758 8 +58864 16599 6 +41171 9506 3 +24903 58555 9 +25005 53515 9 +10609 52860 15 +5597 41960 11 +36251 18231 2 +6503 31288 8 +36667 51591 7 +6358 47180 14 +42496 51227 7 +57510 59691 8 +32300 24602 10 +8682 14805 6 +1451 52645 13 +17133 8704 1 +32034 22657 1 +49305 36751 14 +6376 1521 10 +320 47115 5 +20182 38115 10 +6776 40966 10 +46263 21555 10 +29953 50033 12 +55080 55755 6 +6200 37101 6 +47947 42425 5 +1277 13319 8 +50606 46058 5 +25295 31991 12 +15571 26488 8 +11079 49806 8 +49182 27372 17 +19819 39772 6 +8002 12462 8 +12041 7557 1 +47299 57901 12 +10819 52308 13 +45770 12959 11 +27527 59413 7 +37187 7861 5 +4659 12253 14 +57029 23274 10 +53634 4547 14 +43666 17391 10 +20986 8824 11 +53361 31774 5 +56870 30361 5 +43151 50302 9 +35782 35404 1 +35948 29997 12 +50386 32256 18 +18111 59817 18 +18339 6786 6 +28590 41556 6 +54386 2548 13 +16813 437 7 +40694 47001 5 +8715 28819 7 +42356 1888 11 +51174 15792 14 +36934 35347 11 +23508 37614 6 +53971 27724 11 +17058 8021 1 +47021 27600 7 +27760 23993 6 +57258 43099 17 +10278 20069 7 +53209 50168 9 +25091 38184 10 +24466 25081 9 +41173 20022 6 +54843 6584 12 +47639 10116 3 +41066 31813 6 +8017 59063 7 +42025 43824 14 +13184 3113 1 +55667 42629 12 +55535 34886 16 +40533 1567 12 +29664 48741 1 +18482 24653 5 +36681 48263 8 +9196 15805 1 +26766 17929 9 +18967 16471 13 +43572 26055 6 +41755 36171 7 +29665 16956 13 +58506 14195 11 +10077 822 16 +22530 16498 7 +9809 1153 9 +32926 1995 8 +43130 5908 6 +1409 9324 6 +51890 56210 9 +48598 9977 5 +55372 53348 7 +51916 40175 12 +27336 31445 1 +4038 11182 9 +6869 7604 14 +54658 3201 6 +59982 53902 10 +3896 28765 9 +29219 38451 5 +57300 24549 12 +10666 52085 6 +50718 30046 10 +21699 32609 1 +43321 41551 15 +32690 18158 2 +20176 15629 12 +12993 15083 9 +54630 52275 12 +55341 34742 7 +37629 20536 2 +6574 8101 10 +25025 52963 6 +45097 7170 9 +49748 54202 8 +57627 42270 9 +17281 42812 8 +40058 51336 1 +44861 47046 8 +5481 47348 7 +47984 21588 7 +21831 13090 4 +17377 3905 13 +41592 19477 17 +19813 59849 5 +47407 13502 6 +53864 14271 9 +34816 30721 7 +36833 52266 7 +50130 34561 6 +45656 20906 11 +39774 15004 9 +39119 21176 3 +1584 5856 7 +43888 42284 12 +38134 9046 9 +59800 42762 10 +29114 13009 5 +51238 18205 10 +59474 22607 10 +27360 52300 10 +56947 59607 7 +814 58465 5 +29431 13414 17 +44776 13268 9 +50044 51713 17 +23250 11047 1 +47458 4148 14 +14918 40567 10 +9516 57822 3 +2356 58573 9 +17296 31315 13 +22440 29539 5 +43379 40215 15 +42981 14439 7 +16390 53693 6 +44380 20012 3 +38498 35214 9 +3258 21199 3 +3666 8203 5 +37599 26448 9 +22396 34445 12 +28389 50988 10 +24749 57414 7 +33845 17769 7 +55744 51939 11 +48965 46816 11 +9003 33007 2 +26117 46570 3 +45275 41521 8 +31518 54436 3 +35097 37755 13 +14115 34007 3 +34971 28574 13 +49228 15969 8 +47997 56543 7 +45535 53326 8 +22489 53208 9 +31013 3370 9 +35624 4438 8 +3775 31212 14 +5241 26213 4 +50316 37095 13 +6798 43608 8 +40127 34927 6 +36986 43125 14 +49085 40805 3 +2871 36566 6 +56825 16096 7 +15206 14302 7 +38557 54888 10 +29404 37301 14 +3558 44511 6 +48993 10427 8 +5525 19054 7 +50539 7721 3 +20287 2364 13 +28691 58659 4 +53935 50111 14 +7070 57220 10 +17731 27718 6 +28166 18161 8 +39932 59966 15 +52233 4273 13 +58997 3888 6 +6817 22562 10 +24169 49788 9 +51521 47641 14 +8474 12355 5 +58408 17011 6 +47170 22730 10 +48769 15585 7 +18532 56150 11 +57746 36896 5 +13861 21941 10 +55335 48617 9 +24751 59971 4 +47515 16353 7 +50732 43319 12 +46486 21040 11 +55507 43395 6 +38354 37846 6 +22765 48083 15 +42326 20781 7 +13484 26660 10 +31596 17738 3 +46622 25959 10 +2300 9138 11 +11651 2466 7 +48853 39046 8 +42943 33203 11 +30849 6162 9 +54465 57827 5 +15307 26201 10 +28770 16362 6 +4212 15401 8 +23598 16168 4 +26924 7496 2 +9019 23838 17 +378 45584 4 +48449 12890 13 +33012 36713 8 +36196 30032 11 +20225 56299 8 +36590 30816 8 +18225 9692 9 +34248 17739 14 +17177 2992 13 +37442 54053 11 +38000 32538 15 +18044 47063 4 +59387 4280 8 +36527 38030 15 +12350 2322 5 +40009 39271 11 +25639 40475 13 +49315 40084 9 +16337 45216 9 +30853 55334 8 +23918 501 14 +24753 52961 7 +19616 35468 15 +36979 33278 10 +6202 32146 9 +49359 21408 9 +52461 42173 15 +52643 15830 7 +11793 16808 10 +58831 39057 3 +26558 19420 10 +27997 23116 8 +21664 46945 11 +11064 34764 14 +5178 57064 7 +16576 17337 3 +30377 52357 12 +10251 11666 8 +42577 32605 9 +31081 19101 4 +4128 53810 10 +59261 32421 7 +43309 51508 6 +51614 18914 2 +6386 10165 11 +40348 32749 10 +6424 22050 13 +39577 3750 13 +9478 28209 5 +47749 9648 6 +21061 26842 11 +37304 46306 6 +51732 56072 12 +55140 21002 2 +22686 41292 7 +25955 17612 12 +10613 2904 9 +8857 6534 12 +57662 6069 8 +56071 31203 7 +37015 43363 10 +8398 24220 12 +34022 53140 5 +49301 26057 10 +40394 36625 7 +45329 19726 7 +39958 51159 11 +1490 49460 10 +9945 10771 13 +59061 26091 9 +25238 9289 5 +26165 2745 3 +10177 26446 11 +48668 1189 14 +44591 27572 3 +21001 13026 6 +49949 34192 4 +26806 7612 11 +54170 19936 13 +6417 26818 8 +36234 1066 16 +3860 51407 11 +22172 21942 4 +57136 47309 13 +4783 3496 7 +43721 51 4 +42499 47725 3 +11410 31143 11 +5100 57897 10 +33455 59585 7 +20381 57323 12 +57557 24004 11 +1005 40549 17 +29068 38938 5 +54772 12348 10 +9264 24455 8 +34125 32692 12 +22866 44579 13 +16354 19905 3 +48283 40453 14 +54656 30113 12 +29288 51287 2 +33246 13941 15 +55760 34728 9 +44682 21600 1 +53874 47661 8 +53815 42855 12 +44089 42546 2 +26502 5678 6 +18762 48952 15 +39938 25736 16 +2603 20692 12 +33739 36177 7 +12621 2788 5 +37428 58909 9 +30202 25109 11 +51809 58157 6 +58445 7854 12 +19147 44627 10 +55942 54901 7 +27322 52539 3 +8570 32030 12 +46539 8028 1 +48955 59685 15 +34055 37446 9 +51187 55739 6 +55845 54377 6 +5920 15346 9 +49652 59380 13 +45069 1775 4 +14576 4578 14 +57683 16042 17 +5795 27910 15 +10672 18963 7 +33681 2942 15 +37729 56701 10 +54971 32969 13 +55929 17425 9 +46073 40234 9 +16170 21793 11 +29227 54240 3 +16219 46176 14 +7102 20042 8 +44712 41880 4 +45657 10045 7 +16577 48492 13 +54052 24973 3 +56623 11185 15 +49700 31345 7 +58592 12356 7 +32759 17732 14 +3467 30948 5 +1328 47647 5 +23877 59663 11 +933 4980 13 +6225 21238 12 +29051 36689 7 +54959 26711 9 +48623 57435 5 +26531 57207 4 +29302 22425 15 +2820 29259 11 +47940 42166 11 +53731 38296 8 +7138 22214 2 +45518 57387 9 +40000 52800 16 +32265 18652 12 +9833 30803 15 +18934 37486 7 +31138 7188 1 +11766 28108 7 +15647 32459 3 +19288 9332 6 +57399 45712 6 +8972 6214 10 +9179 40938 11 +28300 25551 3 +51354 17087 8 +20545 32405 10 +56730 15514 7 +56280 41962 13 +48271 16015 14 +25576 21713 2 +43226 2936 10 +51066 45515 6 +40841 20801 2 +34647 58127 16 +59091 37232 6 +14604 50437 7 +16665 45608 1 +49654 50762 11 +51638 47609 5 +35843 24481 11 +4008 2846 2 +55848 19634 11 +22672 25264 10 +14942 44080 8 +7545 38722 9 +39416 51030 8 +45164 8688 9 +24054 26764 18 +16646 2397 11 +12439 44494 12 +40086 23649 4 +36427 49416 5 +8457 18288 12 +31674 46500 10 +20307 24216 10 +54374 28660 5 +39786 39992 3 +36861 2277 12 +1658 11449 3 +30081 22671 6 +11453 28643 8 +27837 6187 15 +53146 59017 9 +55002 2241 11 +3501 14625 16 +27676 7198 13 +47628 10952 7 +24909 48930 11 +48679 19146 10 +5322 36187 6 +20988 33842 2 +55032 6599 11 +21894 47160 14 +59002 14978 7 +49817 18446 6 +23824 52820 11 +31823 45886 7 +22046 21885 7 +9849 15648 5 +11351 49857 10 +14020 43812 12 +49803 23749 9 +34933 19050 15 +11653 10780 13 +46053 36927 15 +47692 15742 6 +9939 53616 11 +35857 13482 7 +23617 26205 10 +16011 21145 14 +59745 7304 14 +36203 9687 9 +50103 2802 3 +12975 20277 13 +47168 31408 14 +44034 11548 10 +14836 39264 10 +3898 57940 5 +958 53565 15 +52910 15724 17 +44789 19562 14 +13964 34328 14 +13951 27375 13 +51117 28651 4 +12080 20207 12 +37134 11945 3 +749 33171 11 +48885 36871 4 +25776 54559 11 +58589 13108 16 +47751 15893 6 +53008 1034 4 +9106 43955 7 +52449 31554 5 +39712 7069 16 +49425 13603 7 +45868 37321 11 +17660 23866 5 +15540 4151 11 +13869 2627 11 +31727 9715 3 +14772 22163 16 +10979 35570 11 +34172 30382 0 +21508 48181 2 +38017 25395 7 +50807 57680 12 +2095 35168 8 +7482 8845 12 +39075 11614 8 +21471 36823 16 +3534 52314 5 +42461 54283 12 +29491 42841 10 +22803 18864 8 +23742 40198 8 +49121 2493 9 +52136 16058 3 +22715 51246 9 +1835 32084 10 +35665 12454 11 +27525 59113 4 +15887 46676 8 +32132 5861 11 +32936 5371 17 +22662 48783 10 +28629 15589 8 +32400 55533 14 +8048 18356 5 +34704 14763 9 +29122 46788 10 +52310 23807 14 +3039 22307 7 +5190 22574 7 +2479 36536 7 +54297 44265 4 +5000 16112 12 +4709 20752 9 +19637 28687 12 +47240 33179 12 +40794 53438 16 +39873 2981 11 +35147 17388 12 +10471 55827 6 +7803 54631 4 +983 18059 6 +1419 26566 17 +7893 16641 16 +5453 44507 13 +10769 5024 16 +20822 16098 10 +7335 34113 11 +8815 19827 5 +9208 29860 8 +56142 449 10 +9139 24929 8 +17557 54587 10 +8674 50137 16 +14337 49627 10 +51465 30282 10 +51312 18847 7 +58932 55743 10 +9403 33262 7 +43423 7658 1 +57967 19191 5 +30132 4699 11 +3676 32006 8 +43904 12614 13 +43429 58394 9 +55000 29506 4 +43194 19747 17 +37891 26904 12 +32496 42730 7 +47339 33821 7 +58736 58701 15 +6008 41086 6 +1302 43316 8 +59014 18681 10 +56075 54424 11 +4960 39848 1 +47743 44390 7 +555 1777 10 +54910 22539 10 +22 40273 10 +46364 44143 4 +41147 27323 13 +41353 38638 8 +24870 3393 4 +7348 25292 11 +27264 29804 7 +42267 41950 9 +57986 20937 12 +52145 17422 7 +31879 58958 13 +32838 5140 12 +49346 30265 9 +794 17462 6 +9464 50532 13 +5431 26102 13 +45016 26929 11 +32360 5627 9 +37920 2899 1 +44267 7857 9 +30634 53345 5 +6296 19463 2 +51832 26577 9 +41951 38469 7 +38289 23257 9 +18259 41861 3 +33432 44522 6 +24215 31571 9 +38646 37549 15 +2817 46586 2 +29320 53563 2 +30180 35711 11 +12671 23952 3 +30066 45713 10 +36519 16229 3 +48076 8271 12 +57274 42404 10 +44927 7375 9 +22223 32618 18 +26576 19241 6 +39968 46943 6 +56576 12609 9 +45966 7951 1 +21051 10580 2 +26725 25604 8 +21362 20651 5 +14272 47859 11 +5771 14679 13 +40661 31321 6 +10445 25577 14 +31166 51681 7 +5936 34902 6 +7108 30125 14 +47460 32674 7 +20168 5126 12 +17386 44843 9 +57422 326 4 +47924 46488 2 +46908 2360 7 +9320 54400 10 +13148 15579 7 +15403 52733 10 +13322 6612 9 +9049 16912 10 +16038 46964 12 +25641 35095 7 +19615 34641 4 +39864 46105 10 +40091 56216 9 +2307 21651 8 +48997 21396 15 +54110 16784 7 +40774 22189 11 +16931 45627 6 +41854 54832 7 +20241 41339 16 +52613 17807 7 +22185 46355 12 +47534 52748 6 +50739 7493 11 +30950 32332 7 +46796 29837 2 +47107 32211 11 +34001 3410 8 +42053 13870 4 +39458 28572 10 +5001 42017 12 +41331 30814 9 +20278 26609 12 +39040 24537 3 +7513 53898 11 +54819 2887 6 +11259 31368 9 +9065 19708 6 +12929 7621 8 +19778 59925 16 +27225 29870 12 +354 56407 9 +18032 54397 9 +20932 32186 8 +23401 53447 3 +978 2211 6 +24173 52237 13 +832 3327 11 +104 36517 2 +48476 52281 5 +51891 44524 9 +26682 42883 11 +6916 4831 17 +17186 25362 17 +3216 57569 9 +36415 37298 13 +51001 2628 10 +28640 1256 11 +53885 45208 16 +5165 37155 10 +21534 42156 1 +15810 20558 12 +30552 38477 9 +58464 52935 12 +46204 12398 5 +34250 43867 7 +50324 39011 8 +28425 43004 14 +12187 9254 10 +18930 30875 6 +4380 19966 3 +3498 33906 9 +24975 32925 7 +45719 10704 13 +6109 34771 7 +35551 59928 10 +28438 38372 10 +58241 10566 7 +17015 436 11 +9262 59288 6 +33642 25318 11 +32068 51410 15 +42304 23648 8 +54840 4668 11 +26669 6297 5 +10992 18256 1 +51815 5707 2 +2067 1600 8 +31198 51474 4 +43686 37635 8 +1900 27721 4 +58101 26332 13 +36622 16197 15 +35760 45829 16 +26948 18753 15 +56258 40252 12 +30611 34544 12 +24862 49934 6 +17527 11868 9 +59426 43821 12 +26125 14811 5 +2743 315 8 +4225 54246 6 +18674 13167 14 +10308 4419 10 +43 5768 16 +32408 22615 8 +50057 2995 7 +47842 23917 4 +14111 35030 10 +18737 49754 4 +31517 6537 5 +55177 49327 7 +22453 17688 8 +43229 56708 9 +51914 12847 8 +8158 34961 2 +52911 25933 16 +4459 56042 16 +38346 30105 6 +51901 44296 2 +36686 31663 7 +5461 8405 3 +10079 54818 15 +37337 41438 3 +27051 28321 15 +10894 12986 10 +47835 51431 8 +7634 42625 4 +27734 22454 16 +46671 52178 14 +18236 43038 6 +38418 27138 10 +28531 33856 2 +38416 44864 7 +10851 13043 8 +22490 53949 7 +49773 572 3 +38601 58631 11 +38664 31562 4 +53390 42020 11 +52545 9743 8 +30545 1290 11 +11554 41495 11 +47254 33530 9 +9936 26277 8 +7641 56346 13 +17148 24321 5 +22646 12861 2 +23182 11177 10 +16785 7421 9 +56822 53577 8 +26177 6278 16 +35521 14927 12 +58814 5002 9 +25219 31010 11 +9185 12383 9 +17940 10965 11 +13304 28678 15 +2713 2622 10 +42906 54529 10 +4815 51561 4 +13241 20070 5 +35730 34946 16 +18037 59354 8 +4941 16733 10 +58397 6733 5 +21446 38158 9 +30456 27488 13 +38407 12582 6 +5159 13880 6 +23806 52147 12 +7549 48139 9 +42538 1073 6 +42527 23759 10 +14907 46895 10 +19681 25015 14 +16282 52157 16 +6414 47231 4 +31827 19689 2 +13751 42321 5 +6163 14492 14 +48455 17061 17 +56569 20386 9 +18992 51512 12 +9767 9588 14 +24164 30272 13 +6545 57496 5 +47361 41118 11 +47103 31840 18 +22015 16818 9 +58666 35535 13 +40074 47678 3 +52694 58484 11 +35875 29756 11 +16702 32923 14 +51872 48389 10 +47514 2722 12 +31841 14466 10 +35528 47988 10 +21801 21873 11 +56023 33793 9 +12552 18614 14 +2979 56234 5 +59819 47455 5 +14973 20722 14 +34925 33738 16 +26100 41825 12 +25379 13738 8 +59613 43549 0 +55694 34337 4 +38047 51091 7 +53411 28093 12 +44702 56755 8 +47549 47392 16 +22457 42181 6 +9459 50052 2 +5262 11155 4 +16820 50100 15 +25 30566 7 +44274 51552 11 +15376 51695 7 +59030 30856 8 +31118 57296 6 +22621 41220 5 +23046 36812 8 +42558 12908 13 +35500 45878 8 +21260 59850 5 +8967 13829 8 +9201 41018 12 +51179 54008 9 +36753 15082 3 +946 9792 10 +58290 19841 6 +34396 28950 5 +3704 39193 10 +48342 45508 7 +51933 27057 15 +46625 1912 9 +53038 7923 8 +25418 8335 8 +240 14956 17 +22282 58141 11 +47987 39382 17 +33754 48168 3 +6303 54726 9 +57695 57763 7 +27750 14728 14 +56232 6104 7 +5722 30990 9 +34578 9995 11 +37840 50798 13 +54563 36440 4 +28066 45426 6 +2857 1385 7 +25306 42498 12 +45896 52793 8 +20723 27132 10 +33896 9677 3 +24337 26739 12 +49300 38334 9 +5831 31860 7 +25691 22139 4 +39456 23043 11 +21108 52127 18 +6430 41627 3 +20252 3747 10 +418 4457 10 +8407 40570 9 +49983 34147 18 +6743 30386 5 +54343 55914 6 +29475 14179 9 +1988 32133 3 +11341 44428 9 +28026 37721 11 +5213 23610 8 +1177 45410 15 +29645 24916 13 +32676 10985 10 +44997 3897 9 +17751 1437 15 +18159 36942 2 +59622 54908 10 +59954 27891 9 +21376 48694 8 +28553 1342 16 +57678 13211 8 +41425 45029 1 +48594 48597 15 +32171 43681 5 +7196 31895 2 +17086 40372 16 +14028 10312 5 +30514 30857 11 +15398 9376 10 +15523 36105 8 +4371 36895 8 +23803 58750 14 +24344 39647 16 +40172 58360 5 +59699 44941 9 +23916 47187 3 +46980 7584 3 +43997 27526 8 +27268 1351 9 +33118 7594 2 +53940 8596 7 +2317 10535 6 +8262 28520 7 +31112 41472 7 +19348 52481 12 +22072 36959 17 +31386 16709 3 +58486 1488 7 +26756 5622 7 +12865 45963 12 +57469 14432 13 +40923 27188 6 +40511 37213 6 +23289 59267 0 +33964 5065 9 +19254 58437 18 +2921 55669 7 +50894 1766 9 +50433 30246 4 +47096 8420 6 +2001 27789 9 +39425 24682 16 +48397 36877 9 +5576 35654 7 +2268 42868 13 +23658 3101 8 +39495 33188 7 +14750 14738 10 +27531 54520 10 +26860 21698 10 +47362 57362 8 +27998 55365 15 +47505 37017 11 +53889 32721 4 +14931 43912 16 +49362 20944 3 +41115 12010 16 +39355 18303 14 +21802 656 2 +26955 14510 8 +16523 45138 6 +8602 37617 9 +28786 7363 3 +46566 45037 4 +52094 19500 12 +44319 5074 6 +5605 46239 5 +23352 44378 14 +6226 27636 9 +32782 8945 11 +36049 53035 9 +48806 30790 3 +31890 38918 3 +28838 57602 17 +14467 58074 3 +35805 41432 3 +36697 46704 11 +33884 1717 5 +3816 6863 11 +59148 3051 3 +44515 45283 6 +11987 22764 7 +31897 30243 7 +26075 56786 7 +15750 54849 10 +53305 59037 3 +27214 2394 11 +42662 5199 16 +9805 53304 9 +13097 58300 4 +8412 31456 13 +32903 30323 11 +50830 13832 7 +26071 15670 15 +35980 38026 14 +49091 47444 8 +1925 16107 10 +13113 8685 7 +25574 47980 8 +19885 36614 11 +52533 4031 10 +3867 50697 16 +49072 51635 7 +59210 16564 7 +57179 48028 16 +41952 28257 8 +40521 15236 8 +49850 25832 9 +31062 10218 13 +3592 4552 4 +16587 25890 11 +54855 43262 6 +3561 3766 9 +56815 48264 10 +54683 37413 6 +36211 35703 12 +36538 3669 14 +40054 10562 3 +4997 49424 7 +24618 6522 5 +3714 52980 9 +34603 37063 11 +23494 13233 2 +35057 56566 10 +27013 59698 3 +45910 31874 8 +45388 20503 15 +41207 42920 10 +45813 17218 12 +20283 26530 6 +55374 47537 14 +5133 21924 9 +45487 14257 13 +48855 47028 12 +3858 6265 12 +56235 6590 15 +14472 39954 4 +11262 29252 5 +3102 31715 9 +29101 31964 7 +30834 53895 18 +2517 47972 7 +16519 52896 5 +21291 8888 9 +44228 26555 12 +37713 32226 15 +46976 48913 5 +33367 21237 6 +27467 39533 4 +7461 35883 14 +30753 11330 9 +41980 53437 14 +6206 38250 6 +56942 22940 6 +8767 47585 7 +20865 53233 2 +43623 41366 7 +10135 37306 15 +3191 3966 9 +6950 9986 9 +16173 37362 12 +4551 21725 14 +45675 22169 5 +13489 59618 13 +3361 3907 10 +25229 9448 16 +19945 10101 11 +15519 43431 9 +42164 42635 15 +49393 38931 10 +30548 14684 7 +44663 35530 10 +7322 24451 6 +19046 44870 14 +30590 57577 10 +28642 8569 12 +35824 42256 15 +30230 33273 14 +34695 30368 4 +5456 30228 7 +49355 56417 5 +58344 13052 13 +1708 38777 10 +57338 57148 11 +47630 44010 14 +36329 5396 6 +11452 44575 12 +41875 51829 16 +7802 39467 7 +21505 4728 8 +34450 35734 8 +28746 44387 7 +51531 27257 9 +21149 24418 5 +1075 52294 7 +18825 2850 13 +33239 20815 8 +42419 927 3 +26940 67 7 +6362 31144 4 +34217 17417 6 +50790 59571 9 +54724 38283 6 +45587 42455 13 +57509 16118 8 +45257 43117 9 +11589 31770 14 +25733 7589 7 +37489 3042 4 +18282 266 6 +1272 24055 11 +27575 41758 12 +54350 55343 5 +34999 19551 5 +47596 27790 8 +57365 33122 8 +36992 31397 7 +33133 54333 8 +51897 7418 15 +7814 25427 8 +2368 3151 12 +22224 49255 6 +18909 15671 7 +18643 58596 11 +52709 34457 9 +38678 21236 12 +26282 17993 12 +9559 39223 15 +29842 9111 10 +43967 17424 10 +14511 29853 2 +22658 38142 8 +33643 54287 16 +24318 21819 10 +10103 18334 12 +2728 25407 14 +17041 14344 9 +31567 25869 4 +49164 3226 3 +44183 20725 9 +6836 35287 10 +7633 5196 2 +776 7713 9 +18999 37668 6 +31614 35340 9 +13458 55614 12 +50866 27594 11 +44638 45954 16 +15821 23904 8 +29365 4209 17 +16293 33206 9 +18464 22429 0 +10413 44295 4 +32304 43952 12 +57430 131 5 +40839 38506 16 +45773 43322 12 +44234 32929 15 +45895 14701 8 +49732 7317 4 +40825 30170 0 +3173 31714 15 +43646 29443 13 +10843 19815 8 +31094 31038 10 +36006 47398 11 +24493 20175 4 +39641 17928 4 +41450 21566 9 +53696 38054 5 +46132 55457 7 +38872 44514 12 +55454 26492 10 +56242 59297 10 +40527 6246 12 +20974 52478 10 +9806 26845 9 +33477 21744 7 +18625 13190 9 +28331 14259 5 +3866 8713 13 +28102 18217 8 +25977 1418 12 +10137 48267 3 +13992 41800 7 +10762 13539 7 +30079 23087 6 +3100 40724 5 +54624 11030 10 +10381 7336 12 +16839 26133 10 +45112 10670 4 +12556 45160 6 +31904 6353 8 +29206 37147 11 +45939 43846 8 +52965 49169 5 +56931 34540 15 +22025 25041 3 +11910 26729 9 +4190 39623 1 +54065 41264 9 +49793 19167 10 +11433 4143 7 +35675 26392 13 +8649 7062 5 +36552 19156 4 +9681 39651 14 +5897 46711 11 +25826 26060 13 +10489 45180 11 +50827 2905 4 +21918 2453 15 +40303 40283 9 +4669 25437 10 +57425 37883 8 +15153 48261 3 +59236 22602 13 +29270 55566 6 +44488 97 13 +20468 17004 10 +43512 21678 14 +6052 23935 9 +26704 7247 4 +16365 3931 16 +55655 22143 2 +50853 41064 13 +59723 52293 4 +19260 51099 16 +30162 12660 16 +36448 631 10 +54116 1980 10 +58815 53725 13 +28415 2292 13 +3954 32239 10 +59132 29081 8 +46234 1582 10 +59196 21094 6 +51823 25750 4 +13412 24438 14 +21405 7570 15 +33840 47040 12 +15500 26026 13 +47508 13700 3 +8700 3923 6 +41876 35380 15 +35056 15285 5 +15605 42438 11 +9217 47140 9 +23596 36867 8 +54245 29391 7 +44288 1174 2 +40467 55145 16 +32091 31271 10 +47105 22363 14 +12122 21131 8 +26937 10673 2 +45600 20513 16 +23273 38754 6 +35655 25009 7 +31659 6995 13 +4483 54719 10 +13360 28824 5 +13650 59330 9 +4725 35077 12 +45936 48497 6 +4759 38770 9 +30850 57956 11 +57371 47059 7 +37177 39817 6 +35602 35735 14 +43235 56602 4 +23445 32442 11 +49984 58658 9 +53908 13383 4 +10460 4848 12 +22558 54147 5 +42305 33876 11 +15426 32736 10 +5508 7897 4 +22119 19008 8 +7498 45280 9 +46469 1671 11 +32139 10235 13 +44218 4174 10 +13998 3774 15 +17195 17292 12 +54635 13800 8 +51102 5484 8 +19836 24433 5 +23413 32679 10 +12879 22899 4 +24020 30416 9 +15472 57328 7 +28994 28189 7 +47771 54125 6 +13129 8639 6 +50984 8008 15 +24619 35215 3 +7772 8341 6 +25967 38088 12 +18125 243 13 +59509 9062 11 +13499 42536 13 +16329 182 8 +37205 45839 9 +20848 28887 9 +35676 16976 15 +810 49457 14 +1345 56919 6 +14925 49006 12 +17315 17485 2 +53117 42679 8 +50887 36100 7 +16065 34702 13 +33967 5973 8 +16549 58373 5 +44664 12101 11 +22001 48840 12 +13975 49478 13 +39515 4019 15 +50428 1635 11 +28261 16786 11 +31646 55970 15 +47194 28206 9 +16527 27092 2 +47417 783 8 +13585 42313 10 +5206 23676 12 +54735 36546 10 +40802 11841 3 +33706 44371 3 +30899 28032 12 +32147 23129 16 +19509 30112 12 +59306 26443 15 +4830 21579 12 +44946 23910 10 +9512 26722 6 +32943 47506 13 +21494 58291 14 +14528 28931 12 +29222 55212 6 +51602 36361 11 +5344 15410 7 +31667 15148 4 +56716 29134 17 +39331 6668 18 +18921 37300 5 +7534 23334 14 +34807 45364 10 +31928 8502 9 +11649 30482 9 +17587 50236 1 +28088 9214 16 +42801 52813 0 +36237 48009 8 +36529 24510 8 +9130 41123 4 +58007 20341 15 +30667 57321 1 +41885 6852 9 +422 54139 16 +2152 15520 6 +46571 17861 9 +44641 38651 18 +965 38454 1 +1760 32725 14 +40167 13651 16 +56550 3203 8 +32053 57531 13 +112 1976 5 +53059 37579 10 +5465 3675 8 +24253 19599 8 +25196 4872 2 +48143 15219 13 +57142 5914 4 +54862 8435 10 +14695 51762 9 +51380 27248 8 +1375 42428 6 +1216 47485 14 +12770 3908 11 +18329 35242 13 +44196 42029 16 +65 2386 12 +22473 39157 1 +42614 3837 4 +22632 6525 8 +32711 24286 11 +42254 22156 8 +45263 37977 5 +53684 165 6 +13255 19529 12 +30316 56246 9 +33461 53176 10 +32096 2186 6 +31922 27339 15 +11600 48697 3 +31469 30900 8 +30453 8204 11 +34762 29366 4 +18860 15006 15 +7293 47975 6 +44449 25806 7 +18936 12910 9 +9946 45532 7 +38005 25460 9 +12860 21218 11 +30339 16355 7 +7829 1071 11 +21888 28945 4 +29678 48513 9 +3597 39132 11 +9409 49600 7 +11479 26248 14 +39749 12060 8 +16267 14434 10 +31962 43708 4 +59102 19924 1 +36991 24603 12 +41518 27110 10 +8811 23265 4 +13879 40614 5 +37536 24855 11 +7879 51488 10 +46315 5201 18 +57110 39087 13 +44337 50148 9 +15185 26139 2 +24366 22735 2 +34092 35593 12 +9975 11594 8 +38846 1867 7 +43277 5477 8 +33692 2450 8 +51923 46597 9 +24660 40140 6 +28221 24513 2 +37146 5784 14 +52084 14812 2 +556 11277 7 +33573 28595 13 +21391 8585 10 +26440 35386 10 +28134 44895 10 +47274 57047 17 +55679 47512 8 +19494 15902 11 +49254 27498 10 +15990 53689 5 +45531 51576 10 +4108 34924 6 +43168 35658 10 +671 4230 3 +40105 46455 12 +6722 20310 14 +49454 38415 3 +3448 26959 8 +9726 770 14 +4599 55380 3 +27071 5972 9 +15796 41258 7 +31779 35978 12 +59510 10803 1 +23644 32108 8 +42203 4240 7 +393 58321 13 +26021 54183 13 +47445 25456 9 +49192 17498 6 +32204 15896 7 +11654 50489 1 +5994 545 9 +38904 45983 6 +8054 51092 6 +18977 3362 5 +48792 35308 14 +2296 26355 8 +30615 36721 7 +12102 32688 7 +51915 31805 6 +14894 21435 7 +49406 33350 3 +863 21623 4 +43759 5867 5 +45788 9863 10 +13571 32842 8 +27066 47807 15 +36341 4766 6 +37392 58983 7 +24325 39583 13 +45623 31983 13 +4531 2570 12 +6539 48874 10 +1292 13923 10 +37741 20495 10 +58972 28463 16 +23556 31632 7 +37483 22599 13 +57291 59432 7 +45394 48391 6 +20630 22142 14 +48482 59640 9 +49746 55873 3 +13512 28965 7 +49999 25907 10 +9678 23882 1 +21580 59054 6 +43978 14498 4 +36068 38865 6 +24817 15156 9 +34934 35128 9 +53671 33013 8 +52061 25302 10 +40674 55903 10 +13042 14584 8 +2084 53472 6 +34617 58454 1 +10578 21202 6 +49555 20564 7 +31468 51899 16 +27346 16204 5 +6040 27847 6 +2426 37518 2 +47326 45994 5 +47261 42231 18 +8445 30240 1 +2616 50243 5 +14306 455 10 +32412 27065 9 +48128 8116 0 +24902 7351 14 +32857 4742 12 +8403 8340 10 +46064 42444 9 +56661 25060 12 +45127 44059 13 +57133 14310 9 +25816 48755 7 +12447 19866 5 +1683 16766 15 +36906 2406 13 +48555 51922 10 +58045 45571 10 +54595 59270 8 +2974 51229 7 +44661 22129 8 +1036 53555 15 +53514 39224 3 +51458 38425 3 +37788 59635 11 +16993 41284 7 +51522 24013 4 +57959 208 7 +3252 40471 7 +55988 2697 10 +25482 26921 17 +13959 6155 11 +23388 9739 10 +32368 11958 12 +53156 35012 3 +49456 37268 15 +47933 26999 9 +40052 28499 4 +47902 39852 3 +27471 1435 11 +23233 31883 10 +47901 51144 8 +32309 26034 13 +21012 51114 6 +32162 21683 2 +42296 59892 13 +6904 26394 9 +2975 33702 4 +11377 23953 4 +14246 21854 13 +36421 38259 9 +56008 46944 3 +5848 53328 6 +4651 58695 8 +27627 49645 8 +36194 26759 15 +642 45201 11 +9635 27492 6 +58502 51685 2 +9746 7838 5 +43927 54036 10 +37585 56396 12 +15104 56940 8 +36754 18609 15 +38633 34662 6 +59224 37336 14 +56364 1829 7 +20169 47730 12 +56541 40594 7 +12837 7686 7 +57211 55337 9 +2927 52529 13 +40036 8482 14 +16983 7399 5 +39126 24948 11 +793 14078 14 +33938 2446 3 +32123 6174 18 +9313 29993 9 +45620 23285 11 +43903 19023 16 +18791 46784 15 +54962 39191 17 +51786 11797 5 +57976 20152 8 +20718 20928 5 +12731 39164 10 +5786 51511 12 +33869 48300 4 +12386 56572 6 +31343 5590 10 +41139 18410 8 +50838 36918 6 +33527 36394 11 +49321 15217 5 +29872 23310 8 +3820 54437 14 +35250 55971 9 +46902 45470 8 +24378 32517 10 +20368 41011 5 +50367 59384 6 +15331 50703 16 +29249 46378 8 +41575 10503 14 +23971 14618 6 +10743 39924 12 +32228 7831 7 +16882 22013 7 +50028 21035 5 +45787 15508 9 +6022 28475 16 +54668 51539 5 +394 14964 2 +26311 53672 11 +7005 41399 4 +9935 58971 11 +14380 6176 15 +4580 55543 9 +44429 34294 13 +52381 46164 5 +40785 2526 6 +21878 32580 8 +46126 14552 6 +37646 35569 10 +59134 49911 7 +54906 22515 11 +59066 30854 8 +27935 4679 4 +52287 19518 6 +212 40870 9 +39030 5110 11 +36094 27232 3 +37082 13340 7 +4268 6797 10 +2458 53050 9 +53584 26417 10 +36592 20731 3 +57145 50482 10 +6319 32932 13 +36661 4454 9 +23720 39061 9 +4918 53863 3 +58118 56510 14 +27759 32253 9 +1475 55705 11 +23026 36508 7 +31781 6721 14 +19531 8871 10 +28326 7268 12 +29995 57958 15 +44464 12576 11 +53575 4731 1 +43977 5796 10 +9114 48868 12 +51936 37111 10 +47251 23727 6 +17898 42655 5 +29987 36309 11 +7825 23883 15 +53069 52703 9 +24866 23447 13 +18802 3088 7 +20818 7093 11 +54553 14099 5 +1604 15683 8 +30727 25504 7 +1657 18312 14 +37192 16970 7 +51394 13517 13 +23332 1273 9 +32218 28763 8 +2985 17709 7 +47680 11476 7 +30354 22128 9 +3037 46910 6 +24756 53525 16 +469 2299 17 +25851 48234 17 +51965 26665 6 +52742 20256 6 +50938 52853 9 +7768 53770 15 +28638 40385 10 +52992 10668 10 +19586 40755 18 +14109 26710 9 +9992 6379 16 +27108 44552 9 +23395 54461 5 +1768 15711 6 +15109 57601 3 +20778 9980 13 +23282 50980 12 +47910 53903 4 +14857 34247 6 +29417 35352 9 +26686 59172 7 +20990 33205 9 +54482 36807 16 +3290 21222 11 +23551 3688 15 +8664 42735 4 +55444 45139 12 +48780 58113 3 +57170 30828 1 +54372 6682 8 +14443 35193 17 +53579 35492 9 +28186 1030 4 +33142 59671 1 +47541 46579 4 +11007 47476 7 +30594 9248 4 +47424 36108 4 +2898 43240 8 +1989 10901 9 +54293 34417 9 +25533 22254 2 +33243 57750 4 +57554 20605 13 +11704 43163 15 +42198 29575 5 +6778 57154 4 +39536 18472 11 +14793 13144 7 +12957 44713 10 +9656 1300 14 +28942 42944 12 +56190 59497 4 +29698 56855 6 +18923 34088 7 +41930 33217 10 +37743 49222 5 +276 32454 1 +2860 59916 17 +3817 12825 13 +33168 38747 11 +31004 48444 10 +41713 50053 9 +49829 33371 10 +32040 36743 11 +27732 56002 14 +57440 51061 1 +3701 14905 8 +51982 57187 18 +10891 35682 11 +2528 59759 4 +55122 34530 12 +300 42993 17 +15489 13263 13 +52328 35645 16 +33862 12967 12 +31008 30077 8 +35838 44021 7 +27709 52186 9 +47803 45489 10 +27024 16139 8 +22944 50933 8 +33355 38069 12 +46644 49811 5 +57580 24933 9 +41664 35815 4 +28710 4673 14 +52722 48124 15 +35580 37999 14 +57995 19714 0 +36878 11748 10 +15102 57894 10 +29370 58825 12 +29537 42772 13 +39916 12442 13 +23170 26415 9 +14873 55820 14 +48829 6294 16 +43243 8662 8 +49946 34980 4 +50155 2476 13 +58682 8532 12 +33578 5967 3 +4251 34128 11 +30978 16787 1 +46085 41364 10 +51348 6567 6 +46932 28058 12 +19677 21292 5 +22699 16969 8 +13473 49861 8 +37435 40489 7 +13891 39083 13 +38267 41658 9 +24696 46645 9 +3412 27312 9 +5274 10497 8 +6560 46585 6 +40626 19899 8 +8990 21778 15 +54978 15267 10 +14980 10384 1 +59412 12096 16 +8782 36466 12 +17051 42249 4 +4972 20796 7 +9814 35491 8 +23349 47667 11 +4762 13955 3 +34466 12945 15 +22012 4966 7 +27249 10408 13 +13807 13188 7 +21433 38765 13 +40745 54273 6 +621 26324 12 +22496 55983 7 +56498 51459 10 +55030 42551 9 +4891 14808 11 +1143 29065 7 +51690 32155 8 +44607 32347 16 +34505 45321 8 +9018 31546 2 +56038 56528 8 +11441 19170 8 +50916 13701 5 +20949 16932 7 +19049 33280 7 +23518 15983 12 +10488 8495 4 +55968 27582 9 +53539 38240 6 +33521 18497 8 +54924 14152 9 +13541 29454 10 +31207 23344 10 +58065 3613 8 +54381 9735 6 +3008 11313 16 +36599 55603 12 +46825 55089 8 +33074 29746 9 +48250 9703 7 +34239 18128 9 +39578 765 10 +56558 24814 3 +11422 17166 9 +30043 10919 1 +12826 31585 9 +3033 56336 4 +52069 22965 14 +52678 22055 12 +19 44670 18 +51197 45553 9 +34399 44443 16 +11855 45431 10 +41561 3166 8 +16722 20242 3 +58069 43700 13 +28466 16520 0 +2711 45168 15 +20709 49114 16 +31450 41722 7 +12056 54256 8 +21739 6614 5 +6371 15424 9 +45274 31251 10 +46369 14581 12 +11795 25656 6 +31100 52560 13 +26202 29962 4 +55047 55161 6 +33397 3383 9 +47501 54680 3 +26612 41362 16 +3176 15811 9 +21311 33166 7 +4179 18599 3 +6867 53303 7 +31255 24592 12 +32792 18689 10 +27231 13177 10 +13201 8338 4 +51827 48585 16 +51383 3153 12 +9152 5111 12 +23006 399 5 +59157 22645 6 +7910 20383 7 +42148 57228 11 +31782 42343 8 +53583 36507 12 +52744 9640 15 +3851 24976 5 +22601 5981 0 +24540 38328 8 +1439 54536 15 +43251 53804 7 +8149 55798 12 +37389 6562 13 +19457 4450 14 +1958 5741 14 +55413 31324 11 +47490 44606 1 +13837 44896 9 +3568 18250 6 +39091 44904 12 +46963 31712 7 +39783 21022 8 +51894 24694 13 +45614 38006 15 +3002 52701 15 +56103 16467 8 +39937 29495 10 +28393 58771 6 +6499 29669 2 +42782 21838 13 +49942 46460 8 +16233 4447 10 +46548 47295 11 +58940 16426 11 +6845 32908 16 +10025 6981 5 +35925 6946 2 +8734 11773 14 +3512 46034 16 +13703 12188 10 +1206 57562 13 +37438 45853 5 +55836 39706 5 +47864 1240 12 +38853 52352 14 +43693 46246 12 +49113 48414 1 +17510 41968 9 +29129 11222 5 +29742 42942 10 +31218 44388 12 +42013 13997 18 +4259 36947 6 +57218 2549 11 +1750 13560 9 +54808 51233 6 +35768 31252 11 +16138 49371 16 +33756 36290 9 +3181 33668 11 +3186 12878 10 +22872 20455 10 +59399 41059 14 +19074 14742 5 +28846 3982 14 +38827 56389 3 +51735 23558 8 +42995 25192 9 +34460 37141 8 +56837 21103 13 +34320 44286 16 +21298 59176 7 +44362 24777 2 +55570 48163 12 +52677 34700 8 +23871 18081 8 +5776 52042 6 +38919 12068 10 +34718 52942 4 +53177 1550 3 +11863 36369 12 +19431 31358 15 +29346 27243 15 +27291 4825 13 +12882 17117 10 +57970 23107 13 +57596 39273 14 +9210 50404 7 +48686 50002 8 +51241 46448 7 +17979 9160 12 +2130 38104 9 +6031 58870 11 +16661 57704 11 +34329 25053 5 +30966 7544 7 +36617 22043 0 +4276 21286 11 +37364 42169 12 +33949 59824 3 +58959 58626 13 +6217 18165 6 +20534 46960 9 +9514 3770 14 +25981 10353 6 +931 606 6 +36200 59572 6 +46107 45173 5 +20742 48607 2 +33204 13681 9 +7631 34665 10 +44505 1806 12 +21422 55284 17 +11477 15140 10 +6351 58584 4 +34822 43689 11 +50042 57074 7 +32292 2840 4 +41126 10162 5 +57581 25080 12 +35430 14049 6 +22362 59274 8 +27864 29696 7 +20911 20282 9 +594 59921 11 +48195 51999 4 +19481 47560 13 +20315 5426 17 +3804 41067 10 +2932 21984 2 +53019 45366 3 +21576 56476 5 +1599 2415 4 +19956 29703 10 +6650 17108 7 +12656 51176 8 +3900 32870 6 +47474 19432 8 +42922 37557 11 +6199 58984 12 +22147 514 10 +8499 24499 16 +44526 27451 9 +2000 27020 6 +24363 25957 6 +27189 1211 3 +24129 54101 2 +22249 51189 10 +8593 46688 9 +25634 12291 13 +48134 32294 12 +8623 22679 10 +46983 11380 5 +47926 18754 15 +42241 2900 13 +59110 18835 10 +22318 14175 7 +36945 26786 17 +25956 16724 12 +6099 17736 6 +854 11723 8 +21323 3929 2 +34528 35230 15 +29207 56939 9 +52781 31024 8 +7274 11284 12 +57025 18422 11 +4875 27010 9 +11075 57631 4 +22236 38388 3 +35031 34138 6 +17455 20118 13 +40272 54486 2 +20186 46171 12 +11561 57541 8 +28993 15171 9 +58974 53807 11 +44381 43112 9 +40812 10872 5 +44732 41092 14 +57777 28328 6 +17852 18911 12 +50363 23994 10 +18665 51707 7 +53112 43276 8 +9736 581 5 +46965 19648 12 +34871 34638 3 +43949 17595 6 +46127 20916 7 +46150 37705 4 +25524 33848 1 +12287 59722 11 +37087 10432 9 +5117 6044 6 +49220 34393 6 +33300 48618 18 +39367 41141 3 +10604 38136 8 +7345 39701 1 +473 8991 7 +24875 15205 10 +35407 48463 5 +48038 21174 5 +34256 58057 6 +57835 27473 8 +52371 21763 9 +50257 25633 9 +30213 45971 11 +54729 50730 11 +28232 50747 10 +20507 25715 16 +51048 21887 5 +56382 52823 11 +55014 19181 4 +44773 7986 7 +4959 20586 9 +3705 49068 6 +25058 46316 16 +8554 51927 10 +42460 14975 9 +53180 35908 2 +53450 19402 6 +16052 48600 8 +35553 18229 8 +29321 45592 11 +27367 33221 7 +39023 47884 4 +42301 38675 7 +17696 55136 11 +2265 43462 14 +17 39663 10 +52025 19991 3 +2810 52477 15 +52553 5504 16 +20171 43135 8 +663 40838 11 +51461 18214 13 +58420 48053 11 +25943 12583 9 +8934 23680 9 +32161 32778 8 +42091 26016 6 +4674 1504 9 +48892 23185 6 +21658 22273 4 +45965 18994 14 +26458 1809 7 +48584 43839 15 +7740 38586 12 +7733 57710 14 +51814 58818 13 +59990 19965 12 +41035 41144 13 +39106 18671 8 +17373 46930 8 +55558 25888 13 +57390 25336 1 +24959 1577 13 +52089 3115 13 +58734 12009 16 +19059 57246 13 +35595 46211 4 +59379 17356 14 +34884 52165 5 +8869 53481 10 +49145 7820 6 +57888 19358 9 +29313 57975 12 +28700 17433 5 +25737 42345 8 +6720 59346 11 +33920 38706 7 +11151 5071 15 +15165 41359 17 +46042 54958 15 +1002 55449 2 +56377 57368 4 +33291 38996 15 +10593 17614 15 +58073 53948 9 +51997 40222 7 +1165 26335 3 +4458 45324 13 +39175 52773 3 +51931 817 10 +21193 312 17 +23157 39870 9 +16861 33772 6 +4737 41549 11 +44147 18682 12 +27883 53175 8 +33612 23999 11 +10182 49520 10 +21903 31309 9 +35855 51039 12 +16494 12097 10 +10824 20833 5 +29242 31101 8 +26454 48945 8 +19807 51730 17 +24857 8560 12 +23474 28599 8 +19594 32055 1 +30671 59952 6 +43361 43954 11 +23094 10352 7 +2447 43263 13 +35929 12569 8 +32376 50034 9 +27154 9996 13 +27007 15882 9 +42955 17066 11 +58228 24988 7 +26688 52514 8 +20177 50278 8 +59250 15211 13 +40997 39513 14 +24556 31523 16 +51069 56678 12 +50143 29239 8 +413 34761 13 +53108 43109 11 +4587 39519 14 +32097 11931 9 +56988 17999 14 +29691 9794 16 +52273 44786 7 +32236 33275 16 +5599 46637 6 +39190 6853 12 +42678 11252 12 +59409 17067 13 +2075 3132 3 +17647 5427 13 +54292 19045 11 +36036 31498 7 +33018 39649 15 +31245 10997 5 +55475 13295 8 +3365 1891 15 +39484 46048 8 +9492 44159 1 +43412 39201 13 +56938 2365 11 +44312 33339 4 +8866 32575 7 +18956 11140 12 +59844 35901 10 +18904 42755 9 +861 53449 7 +15368 47440 3 +25808 16012 8 +17951 32626 12 +52579 59501 11 +23708 33923 7 +17944 45960 4 +34159 43048 10 +32559 23478 5 +24956 46701 18 +37551 23292 12 +20749 3434 1 +3129 30143 6 +22251 3713 6 +28561 9790 3 +8353 35360 8 +30610 20330 16 +19592 27368 16 +4854 44842 4 +54787 7039 9 +54056 46787 13 +32803 24437 10 +33335 28879 9 +46160 31381 9 +49677 25642 15 +2843 38744 1 +17210 53297 0 +9004 47067 10 +2202 59290 3 +57172 28027 9 +36500 6402 15 +51313 41812 9 +226 47510 12 +58308 2031 11 +14601 21023 9 +14281 38870 17 +2968 39154 11 +50701 28279 18 +45471 17938 2 +32433 36199 17 +21167 41146 10 +21654 47331 11 +23646 32720 11 +58180 37881 1 +20879 32874 17 +23477 25763 9 +40639 53020 12 +42850 42833 13 +26784 42314 8 +24124 26099 3 +45792 8591 4 +3004 46294 1 +41918 9343 16 +35643 18627 6 +20704 13488 9 +57538 25804 6 +29221 48062 14 +41630 5821 14 +42829 12416 9 +20205 55919 2 +6396 289 10 +8942 28719 14 +14276 32463 0 +48169 39162 8 +27859 46157 3 +14129 25480 9 +14322 2399 10 +38100 46843 4 +38311 42748 8 +30770 57461 11 +3682 37052 5 +26349 31960 12 +15066 13445 8 +55572 20073 14 +26903 59324 6 +22559 59329 11 +35019 42474 11 +55635 9140 4 +36936 58066 6 +8109 27752 10 +23851 47913 6 +35959 56726 9 +34185 31886 9 +47750 18803 6 +11839 55395 13 +51078 34154 16 +34983 32021 18 +33789 41289 1 +367 38617 8 +2841 28219 15 +11274 39742 13 +21262 21466 7 +4191 33792 7 +51362 35617 13 +46236 14071 7 +57053 57084 8 +32882 54449 18 +21624 53415 14 +57050 51763 12 +20105 32731 13 +57308 28884 11 +13579 51264 7 +43917 50610 13 +47418 35429 10 +7690 16246 17 +21714 9511 6 +2139 54360 14 +34992 45757 7 +14988 3822 10 +35752 15187 6 +41200 47767 10 +12899 43932 8 +47192 21358 3 +9702 33353 15 +33000 28487 7 +5057 46451 11 +59403 11922 13 +34734 9751 17 +42934 56206 7 +18574 25117 16 +53158 9956 11 +31564 52837 9 +16103 43493 16 +4593 22771 8 +58664 17499 11 +6756 17729 9 +44472 27280 7 +20149 58730 8 +33511 56294 12 +997 52602 2 +8183 48626 8 +3279 41203 16 +13270 21513 9 +17804 34824 17 +28551 41891 11 +14128 25369 10 +21703 38075 7 +50453 38340 2 +34134 59760 5 +207 9810 12 +36904 49789 5 +12535 57013 14 +26321 7150 9 +5643 30818 7 +1669 8080 7 +39048 56529 12 +16313 46707 6 +31762 40917 7 +52548 6839 4 +19140 48860 10 +3164 8702 18 +27566 55052 16 +764 3049 9 +41436 23590 10 +18445 53165 7 +22481 23822 8 +36759 23130 7 +39074 30385 11 +49498 37717 7 +45006 47867 1 +11090 32919 17 +30960 44102 9 +10514 41473 6 +15098 7398 13 +41901 56610 9 +9178 28697 15 +39088 31845 15 +41817 38344 18 +17364 10629 10 +20964 32577 10 +29769 19235 13 +4373 47768 8 +2111 1449 8 +20563 7508 9 +53848 18113 8 +2699 3663 17 +52750 41077 7 +29979 47747 16 +11595 12468 13 +53955 16154 12 +59888 4909 17 +5992 37687 13 +2474 56424 6 +49854 5999 18 +30350 49536 11 +17344 56922 8 +3601 34451 8 +26594 3961 17 +50473 55782 11 +53198 37885 14 +10458 55921 10 +52900 40620 11 +44436 12919 14 +52501 42641 7 +9921 50981 10 +5948 19404 10 +32554 2421 9 +43093 52049 15 +46601 56418 8 +2422 54801 10 +12088 47642 7 +31259 5360 16 +15816 8354 3 +1810 224 6 +37552 5449 7 +10898 8370 6 +57661 7233 10 +46474 35174 18 +27454 12394 2 +1404 11213 16 +27591 37284 7 +1767 26540 6 +45802 51948 16 +18796 51288 7 +42903 45462 11 +54660 32087 6 +9842 5632 7 +19593 40887 13 +42865 2147 0 +44747 19225 2 +56768 26782 3 +38013 22257 12 +15669 3005 4 +17528 59351 11 +43095 52822 7 +52652 10707 6 +607 15601 15 +45996 847 5 +26960 55031 2 +10141 52386 6 +35333 24350 6 +45157 57484 14 +48624 19388 3 +19043 17224 13 +36573 16598 2 +30302 22427 8 +15311 10639 4 +38376 56571 11 +29988 14030 11 +39751 49896 11 +4672 34395 14 +5210 14414 6 +5875 33427 3 +57900 32200 10 +38589 40607 10 +47977 4881 4 +54361 58187 14 +6481 4308 15 +24495 13109 3 +22123 32458 12 +19327 12981 10 +39045 37460 14 +37157 21247 3 +14440 45098 12 +32636 32052 13 +37622 46069 3 +44151 12784 3 +30103 12792 18 +7453 34489 17 +17578 38767 14 +13209 59233 10 +17214 50840 2 +2724 41502 13 +11897 56344 14 +55437 3906 2 +24274 32582 9 +45002 12138 8 +26943 11806 8 +50914 11353 10 +44110 35143 7 +4196 53847 12 +18741 18419 9 +59747 44618 14 +44820 9245 9 +55094 34478 12 +6058 12293 11 +11812 54786 3 +22373 41263 5 +7022 30506 5 +56483 31363 13 +27927 29186 15 +10313 14677 10 +16638 34950 3 +53324 18658 9 +18261 8489 1 +13375 57829 7 +4339 15378 8 +12260 35072 11 +34305 28816 0 +44602 27202 7 +43995 46817 14 +2783 38619 6 +44613 16779 5 +7997 51315 14 +21039 36116 5 +176 43041 13 +3490 56436 0 +42111 12702 3 +42090 48349 11 +28479 13125 5 +46885 25944 15 +33469 41736 8 +31285 58114 6 +20511 50522 17 +14393 15431 6 +34091 6312 5 +50584 42158 8 +16073 19614 9 +15885 47851 9 +24919 28100 10 +47736 42935 5 +44936 55482 12 +16958 21769 2 +32625 57193 1 +24730 15399 5 +36894 53054 5 +33750 14238 8 +12963 3221 14 +46618 28044 7 +4667 58727 10 +29745 55447 14 +49515 2913 8 +24663 45450 10 +35740 46957 7 +2132 8964 7 +57688 52917 12 +59206 7092 13 +7473 12934 10 +25393 56331 10 +31595 11370 10 +30114 28284 8 +57849 23920 6 +15744 47757 11 +19547 4944 1 +24578 41683 8 +58897 41923 4 +17571 15697 10 +49554 9197 7 +42177 39266 15 +1304 20492 3 +40490 7362 10 +6369 32098 8 +52092 47475 12 +7921 34402 2 +57450 28683 12 +41163 36311 6 +18405 22316 18 +9871 4803 11 +52663 34133 8 +24224 37060 15 +56953 39750 10 +50772 40003 1 +18740 1337 14 +25233 44516 16 +26424 23724 12 +48568 41785 12 +32277 54209 5 +16415 46083 2 +56432 741 16 +11067 22464 9 +33762 40102 18 +7224 26197 6 +34840 36603 13 +1061 37316 17 +37163 51166 10 +357 14072 7 +52343 22575 9 +9701 59033 5 +695 57182 8 +32293 9891 2 +46578 39517 16 +37353 18561 16 +10487 38784 9 +56255 26308 8 +35349 11563 5 +34439 48665 11 +40877 17914 5 +20427 38033 3 +43502 24661 9 +27469 43249 9 +41303 16113 13 +995 4533 13 +16615 34182 9 +15517 44690 15 +13727 22833 5 +58272 2363 12 +12114 30734 6 +41165 39857 4 +6593 51881 8 +48140 1515 14 +14654 23192 11 +52739 47181 12 +54469 52201 16 +41695 58492 6 +45667 38164 6 +24734 32014 8 +2738 37921 2 +46946 48527 11 +34865 45722 9 +58081 45174 18 +23615 58032 6 +13290 40087 9 +34719 35291 15 +56906 30998 16 +54943 9038 0 +49023 32440 6 +1142 28897 16 +57679 15434 5 +44162 49832 4 +5570 43915 1 +11747 53737 11 +3506 51724 10 +50377 28915 12 +41830 4390 3 +39295 27054 7 +34152 47526 5 +14350 34635 11 +35395 46757 5 +41570 1391 2 +8049 11780 7 +33108 2890 1 +16921 41553 0 +49878 17597 10 +51945 38325 14 +58382 25638 12 +13519 26887 4 +7864 22712 6 +27912 58995 8 +48706 1562 12 +23085 7123 7 +49887 2597 8 +33110 3376 1 +24149 31217 8 +36782 8034 15 +26059 59012 1 +24035 8483 9 +28600 18392 11 +22008 3228 7 +51505 6266 6 +24063 43101 5 +11219 18175 12 +1430 15889 8 +36412 51058 8 +29984 29387 15 +21382 12382 3 +37234 11740 6 +21723 33058 14 +56122 37383 7 +46739 53461 13 +44724 17413 2 +29203 52429 0 +10519 28528 4 +301 49003 16 +4137 32065 3 +37303 18729 7 +11576 13901 6 +34890 23815 14 +35993 13546 12 +15511 44260 5 +16763 1917 9 +27286 18573 13 +19304 46668 5 +36168 24581 6 +39144 13530 17 +48776 51693 10 +2509 7338 9 +25201 36700 14 +47111 49924 8 +15222 58025 14 +25147 11271 4 +8812 11395 1 +4907 59839 14 +6573 51314 8 +34263 18933 9 +2083 25133 8 +45574 50876 4 +38317 14691 4 +20989 24238 5 +27517 4996 7 +20250 13897 13 +4641 7466 4 +25030 32105 14 +48506 57266 3 +51571 24181 10 +56456 5572 10 +46337 29572 13 +44746 43010 13 +30848 53329 6 +53027 33079 0 +21084 8839 7 +16424 20101 10 +36353 26932 3 +21855 2191 8 +52710 20474 2 +55794 26803 10 +35445 24475 8 +3739 20903 7 +4376 4607 5 +40889 2072 10 +36014 37365 7 +6989 40121 4 +39644 23099 4 +27074 4507 10 +8099 9137 7 +2219 40206 11 +18029 44083 9 +46958 29453 11 +46532 6848 8 +18151 20051 8 +31891 18171 5 +39407 2813 2 +50687 19051 9 +47813 54100 16 +25729 16347 5 +34555 8880 3 +22040 573 1 +25628 47557 3 +52047 9258 2 +31625 45796 3 +24960 28758 11 +17487 11307 7 +51665 42147 16 +9263 44666 13 +48897 17567 6 +15709 43106 13 +24904 45385 2 +36935 51800 14 +37281 6072 16 +37610 6551 8 +2633 55344 16 +40741 38751 7 +22261 47815 8 +59860 5452 8 +53798 3865 14 +36892 26550 4 +6793 52476 4 +5204 24864 6 +42224 2971 8 +13606 4077 7 +11746 22647 5 +27965 18331 12 +42371 46300 6 +16477 41017 17 +15787 59574 9 +50585 16688 9 +13707 29500 5 +40014 15897 13 +17943 6618 9 +46032 36516 14 +26923 49014 0 +23240 3091 5 +9601 10936 16 +56449 32217 8 +37876 5176 8 +19558 12948 13 +50492 52082 1 +9504 35629 17 +9856 9770 6 +32189 41866 9 +43688 34527 9 +5812 37078 11 +42487 39405 5 +11008 26336 13 +57196 16832 12 +19115 28545 3 +9987 36734 1 +14656 37107 8 +38274 14937 4 +43001 13326 18 +56778 46656 2 +5739 687 15 +1091 9098 8 +7875 55126 9 +6952 11640 15 +42505 43033 4 +52978 30264 7 +5951 33430 13 +32114 36733 7 +37756 48293 5 +8411 36120 4 +39197 40827 9 +6178 26257 14 +18026 47819 6 +40194 26560 12 +56648 55233 9 +40665 9325 14 +3324 26298 7 +26574 3759 13 +12923 26225 9 +36273 41959 2 +55910 13822 5 +23244 18644 14 +30972 56309 7 +54794 22827 7 +13312 29628 6 +32976 20676 13 +12642 22867 6 +52892 36741 8 +37510 35807 9 +51836 13787 4 +3296 55160 13 +41283 51434 3 +10009 4790 3 +43862 10029 11 +33977 5325 14 +47875 48412 1 +8547 64 13 +31992 17930 7 +37609 54380 6 +58791 36376 9 +32381 5242 13 +30673 19033 7 +56029 9445 10 +26883 53703 11 +59781 25380 5 +45190 16859 9 +53049 28126 3 +41477 9773 6 +56674 16937 8 +19011 47734 2 +59687 25438 10 +19448 6136 15 +29587 11959 7 +9011 34735 5 +30882 48277 8 +17542 45970 9 +9873 8819 13 +24872 41273 6 +54211 58515 11 +43664 56987 10 +57590 46766 13 +33866 19464 11 +24991 11591 16 +18379 30149 5 +17586 46479 1 +33091 51087 9 +17306 7507 10 +36722 24610 8 +45483 12623 15 +55159 15988 17 +52938 35390 7 +25584 1916 0 +33167 9782 14 +28605 31867 12 +13176 55623 16 +20388 38648 5 +15994 35011 4 +10669 21766 1 +33332 2696 10 +53851 18237 5 +24527 37947 11 +8671 51207 17 +36123 42651 11 +53586 13849 11 +11286 47155 4 +45798 45702 14 +44688 24629 4 +6762 32488 8 +2524 11338 8 +57109 46936 2 +54262 22064 6 +21719 11316 13 +7403 30837 12 +35951 51961 6 +23189 12587 7 +10470 52802 5 +37573 9780 9 +51992 49032 5 +126 31159 10 +4136 14036 7 +42513 37591 9 +42554 40601 9 +2005 34951 13 +47478 2467 12 +48659 12164 13 +50495 9645 8 +34403 50261 2 +12955 58313 4 +15207 24788 11 +48073 34180 10 +48609 20089 14 +57438 8825 10 +55763 31146 11 +32757 4537 13 +55671 633 1 +41668 51843 11 +58422 31475 15 +45661 33514 10 +46302 6640 2 +46832 53113 14 +12177 47132 8 +49031 19626 7 +1591 17812 10 +35762 32612 9 +16699 48877 3 +3850 10338 5 +55528 58240 6 +2190 59578 10 +42953 40270 13 +25203 8706 9 +3539 10156 6 +53337 50890 15 +298 44115 11 +15405 54135 11 +29363 51621 14 +25648 44476 14 +57545 56304 18 +24121 43002 2 +44958 14562 5 +258 27450 16 +31326 936 16 +9764 58342 15 +27333 15015 3 +40368 16568 16 +1938 24476 3 +26519 52053 14 +42272 40476 11 +143 9600 4 +5797 3588 18 +32998 8246 5 +37750 54734 12 +25035 27094 6 +18985 47964 17 +24516 20703 12 +28841 15539 4 +54687 17785 18 +31223 45783 7 +46552 23308 2 +38625 369 13 +15752 47735 5 +24066 50285 12 +33621 9855 10 +30295 43947 10 +12460 15808 11 +33080 28488 4 +59044 58417 5 +15682 18780 6 +44137 45460 10 +32313 22179 1 +11579 1681 2 +6139 28864 13 +17250 21479 5 +31020 25918 1 +32975 9597 7 +58250 30916 9 +53854 59972 8 +46953 12872 3 +35325 17227 12 +26610 1310 1 +13419 35123 12 +41023 25284 8 +21404 56212 15 +21144 35228 8 +19856 21900 6 +13658 38076 10 +48130 33656 16 +5823 10147 9 +6815 56898 7 +16637 4013 9 +53188 20642 7 +46699 54654 16 +27103 2861 12 +30190 17602 15 +7712 28433 16 +34548 50765 11 +8818 42046 8 +12025 27107 16 +10420 45554 4 +14744 27558 10 +21609 18928 14 +18834 46103 8 +35104 10507 11 +46233 42815 17 +40444 16791 6 +50409 20239 7 +47152 55215 9 +30134 53947 9 +25069 30562 11 +12881 59581 11 +30137 24034 1 +23138 16823 9 +13316 46312 13 +1053 58346 9 +57520 17503 2 +532 23236 14 +59257 21321 7 +22542 8439 12 +42466 12226 8 +22883 30267 11 +47853 40548 13 +57085 38913 16 +55373 22051 6 +38850 8397 8 +5239 36048 4 +33624 44783 8 +28587 56694 15 +8851 13152 17 +31977 452 7 +57249 41340 6 +10186 44616 17 +11694 41376 0 +53125 53092 12 +2600 14653 11 +33030 3127 12 +26184 7006 9 +10552 7518 15 +5346 59540 14 +58332 58622 14 +23901 53137 16 +30088 8162 1 +47599 34011 8 +15218 40986 10 +49717 6651 4 +58524 47520 10 +22321 57619 11 +18865 41462 7 +6546 43893 11 +9904 37109 11 +23178 18743 7 +56733 11609 14 +13236 26907 6 +2609 37041 14 +40985 18668 11 +42884 43670 12 +6405 37212 10 +17275 38516 9 +11146 15740 15 +19922 23619 13 +37558 16085 5 +25630 59584 8 +1324 39897 5 +32806 543 13 +5234 16099 8 \ No newline at end of file From 146d0eb2c1a222014342646758aea152a3158488 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 15 Nov 2022 14:38:19 +0800 Subject: [PATCH 002/601] Update kb.py add ClsKB and RegKB --- abducer/kb.py | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/abducer/kb.py b/abducer/kb.py index 032731c..0ba1479 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -115,7 +115,80 @@ class add_KB(KBBase): def __len__(self): return sum(self._dict_len(v) for v in self.base.values()) +class ClsKB(KBBase): + def __init__(self, X, Y = None): + super().__init__() + self.base = {} + + if X is None: + return + if Y is None: + Y = [None] * len(X) + + for x, y in zip(X, Y): + self.base.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) + + def get_candidates(self, key, length = None): + if key is None: + return self.get_all_candidates() + + length = self._length(length) + + return sum([self.base[l][key] for l in length], []) + + def get_all_candidates(self): + return sum([sum(v.values(), []) for v in self.base.values()], []) + + def _dict_len(self, dic): + return sum(len(c) for c in dic.values()) + + def __len__(self): + return sum(self._dict_len(v) for v in self.base.values()) + +class RegKB(KBBase): + def __init__(self, X, Y = None): + super().__init__() + tmp_dict = {} + for x, y in zip(X, Y): + tmp_dict.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) + + self.base = {} + for l in tmp_dict.keys(): + data = sorted(list(zip(tmp_dict[l].keys(), tmp_dict[l].values()))) + X = [x for y, x in data] + Y = [y for y, x in data] + self.base[l] = (X, Y) + + def get_candidates(self, key, length = None): + if key is None: + return self.get_all_candidates() + + length = self._length(length) + + min_err = 999999 + candidates = [] + for l in length: + X, Y = self.base[l] + + idx = bisect.bisect_left(Y, key) + begin = max(0, idx - 1) + end = min(idx + 2, len(X)) + + for idx in range(begin, end): + err = abs(Y[idx] - key) + if abs(err - min_err) < 1e-9: + candidates.extend(X[idx]) + elif err < min_err: + candidates = copy.deepcopy(X[idx]) + min_err = err + return candidates + + def get_all_candidates(self): + return sum([sum(D[0], []) for D in self.base.values()], []) + + def __len__(self): + return sum([sum(len(x) for x in D[0]) for D in self.base.values()]) if __name__ == "__main__": pseudo_label_list = list(range(10)) @@ -130,4 +203,28 @@ if __name__ == "__main__": print() res = kb.get_candidates(7, length = 3) print(res) + print() + + X = ["1+1", "0+1", "1+0", "2+0", "1+0+1"] + Y = [2, 1, 1, 2, 2] + kb = ClsKB(X, Y) + print(len(kb)) + res = kb.get_candidates(2, 5) + print(res) + res = kb.get_candidates(2, 3) + print(res) + res = kb.get_candidates(None) + print(res) + print() + + X = ["1+1", "0+1", "1+0", "2+0", "1+0.5", "0.75+0.75"] + Y = [2, 1, 1, 2, 1.5, 1.5] + kb = RegKB(X, Y) + print(len(kb)) + res = kb.get_candidates(1.6) + print(res) + res = kb.get_candidates(1.6, length = 9) + print(res) + res = kb.get_candidates(None) + print(res) From bc5fd2342f86ed24c3e944f66ea9c64ec358a168 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 15 Nov 2022 14:47:24 +0800 Subject: [PATCH 003/601] Update get_mnist_add.py --- datasets/mnist_add/get_mnist_add.py | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/datasets/mnist_add/get_mnist_add.py b/datasets/mnist_add/get_mnist_add.py index d05f477..167ee57 100644 --- a/datasets/mnist_add/get_mnist_add.py +++ b/datasets/mnist_add/get_mnist_add.py @@ -3,35 +3,22 @@ import torchvision from torch.utils.data import Dataset from torchvision.transforms import transforms -class MNIST_Addition(Dataset): - def __init__(self, dataset, examples): - self.data = list() - self.dataset = dataset - with open(examples) as f: - for line in f: - line = line.strip().split(' ') - self.data.append(tuple([int(i) for i in line])) - - def __len__(self): - return len(self.data) - - def __getitem__(self, index): - i1, i2, l = self.data[index] - return self.dataset[i1][0], self.dataset[i2][0], l - def get_mnist_add(): transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081, ))]) - train_dataset = MNIST_Addition(torchvision.datasets.MNIST(root='./', train=True, download=True, transform=transform), './train_data.txt') + train_dataset = torchvision.datasets.MNIST(root='./', train=True, download=True, transform=transform) test_loader = torch.utils.data.DataLoader(torchvision.datasets.MNIST('./', train=False, transform=transform), batch_size=1000, shuffle=True) + X = [] Y = [] - for i1, i2, l in train_dataset: - X.append([i1, i2]) - Y.append(l) + with open('./train_data.txt') as f: + for line in f: + line = line.strip().split(' ') + X.append((train_dataset[int(line[0])][0], train_dataset[int(line[1])][0])) + Y.append(int(line[2])) + return X, Y, test_loader if __name__ == "__main__": X, Y, test_loader = get_mnist_add() print(len(X), len(Y)) print(X[0][0].shape, X[0][1].shape, Y[0]) - \ No newline at end of file From 523d741c8dd540961fef2d8b495314ea00a6c296 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 15 Nov 2022 14:53:24 +0800 Subject: [PATCH 004/601] Update kb.py --- abducer/kb.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 0ba1479..af4c8ec 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -115,7 +115,7 @@ class add_KB(KBBase): def __len__(self): return sum(self._dict_len(v) for v in self.base.values()) -class ClsKB(KBBase): +class cls_KB(KBBase): def __init__(self, X, Y = None): super().__init__() self.base = {} @@ -128,6 +128,9 @@ class ClsKB(KBBase): for x, y in zip(X, Y): self.base.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) + + def logic_forward(self): + return None def get_candidates(self, key, length = None): if key is None: @@ -146,7 +149,7 @@ class ClsKB(KBBase): def __len__(self): return sum(self._dict_len(v) for v in self.base.values()) -class RegKB(KBBase): +class reg_KB(KBBase): def __init__(self, X, Y = None): super().__init__() tmp_dict = {} @@ -159,7 +162,10 @@ class RegKB(KBBase): X = [x for y, x in data] Y = [y for y, x in data] self.base[l] = (X, Y) - + + def logic_forward(self): + return None + def get_candidates(self, key, length = None): if key is None: return self.get_all_candidates() @@ -207,7 +213,7 @@ if __name__ == "__main__": X = ["1+1", "0+1", "1+0", "2+0", "1+0+1"] Y = [2, 1, 1, 2, 2] - kb = ClsKB(X, Y) + kb = cls_KB(X, Y) print(len(kb)) res = kb.get_candidates(2, 5) print(res) @@ -219,7 +225,7 @@ if __name__ == "__main__": X = ["1+1", "0+1", "1+0", "2+0", "1+0.5", "0.75+0.75"] Y = [2, 1, 1, 2, 1.5, 1.5] - kb = RegKB(X, Y) + kb = reg_KB(X, Y) print(len(kb)) res = kb.get_candidates(1.6) print(res) From 196483e23f48c1e4d85b8934adec56bc1ad81d8f Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 15 Nov 2022 15:54:12 +0800 Subject: [PATCH 005/601] Update abducer_base.py --- abducer/abducer_base.py | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 15badf6..f990013 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -17,6 +17,26 @@ import numpy as np def hamming_dist(A, B): return np.sum(np.array(A) != np.array(B)) +def hamming_dist_kb(A, B): + B = np.array(B) + A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) + return np.sum(A != B, axis = 1) + +def confidence_dist_kb(A, B): + B = np.array(B) + + #print(A) + A = np.clip(A, 1e-9, 1) + A = np.expand_dims(A, axis=0) + A = A.repeat(axis=0, repeats=(len(B))) + rows = np.array(range(len(B))) + rows = np.expand_dims(rows, axis = 1).repeat(axis = 1, repeats = len(B[0])) + cols = np.array(range(len(B[0]))) + cols = np.expand_dims(cols, axis = 0).repeat(axis = 0, repeats = len(B)) + return 1 - np.prod(A[rows, cols, B], axis = 1) + + + class AbducerBase(abc.ABC): def __init__(self, kb, dist_func = "hamming", pred_res_parse = None, cache = True): self.kb = kb @@ -83,17 +103,19 @@ if __name__ == "__main__": abd = AbducerBase(kb) res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 0) print(res) + print() res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 1) print(res) + print() res = abd.abduce(([1, 1, 1], 4), max_address_num = 1, require_more_address = 1) print(res) print() - print('Test cache') res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 0) print(res) - res = abd.abduce(([1, 1, 1], 4), max_address_num = 20, require_more_address = 1) + print() + res = abd.abduce(([1, 1, 1], 5), max_address_num = 2, require_more_address = 1) print(res) # res = abd.abduce(([0, 2, 0], 0.99), 1, 0) # print(res) - \ No newline at end of file + From 83dff66d9ff4b8871b8496c9cd75536625bfc070 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 15 Nov 2022 20:04:27 +0800 Subject: [PATCH 006/601] Update kb.py --- abducer/kb.py | 123 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 111 insertions(+), 12 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index af4c8ec..c3ddff0 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -17,7 +17,7 @@ import numpy as np from collections import defaultdict -from itertools import product +from itertools import product, combinations class KBBase(ABC): def __init__(self): @@ -80,20 +80,30 @@ class add_KB(KBBase): def get_all_candidates(self): return sum([sum(v.values(), []) for v in self.base.values()], []) - def get_abduce_candidates(self, pred_res, key, length, dist_func, max_address_num, require_more_address): + def get_abduce_candidates(self, pred_res, key, max_address_num, require_more_address): if key is None: return self.get_all_candidates() candidates = [] - all_candidates = list(product(self.pseudo_label_list, repeat = len(pred_res))) - for address_num in range(length + 1): + + for address_num in range(len(pred_res) + 1): if(address_num > max_address_num): print('No candidates found') return None, None, None - for c in all_candidates: - if(dist_func(c, pred_res) == address_num): - if(self.logic_forward(c) == key): - candidates.append(c) + + if(address_num == 0): + if(self.logic_forward(pred_res) == key): + candidates.append(pred_res) + else: + all_address_candidate = list(product(self.pseudo_label_list, repeat = address_num)) + address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) + for address_idx in address_idx_list: + for c in all_address_candidate: + pred_res_array = np.array(pred_res) + pred_res_array[np.array(address_idx)] = c + if(np.count_nonzero(np.array(c) != np.array(pred_res)[np.array(address_idx)]) == address_num and self.logic_forward(pred_res_array) == key): + candidates.append(pred_res_array) + if(len(candidates) > 0): min_address_num = address_num break @@ -101,10 +111,14 @@ class add_KB(KBBase): for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): if(address_num > max_address_num): return candidates, min_address_num, address_num - 1 - for c in all_candidates: - if(dist_func(c, pred_res) == address_num): - if(self.logic_forward(c) == key): - candidates.append(c) + all_candidate = list(product(self.pseudo_label_list, repeat = address_num)) + address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) + for address_idx in address_idx_list: + for c in all_candidate: + pred_res_array = np.array(pred_res) + pred_res_array[np.array(address_idx)] = c + if(np.count_nonzero(np.array(c) != pred_res_array[np.array(address_idx)]) == address_num and self.logic_forward(pred_res_array) == key): + candidates.append(pred_res_array) return candidates, min_address_num, address_num @@ -114,6 +128,91 @@ class add_KB(KBBase): def __len__(self): return sum(self._dict_len(v) for v in self.base.values()) + +# class hwf_KB(KBBase): +# def __init__(self, pseudo_label_list, max_len = 5): +# super().__init__() +# self.pseudo_label_list = pseudo_label_list +# self.base = {} + +# X = self.get_X(self.pseudo_label_list, max_len) +# Y = self.get_Y(X, self.logic_forward) + +# for x, y in zip(X, Y): +# self.base.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) + +# def logic_forward(self, nums): +# return sum(nums) + +# def get_X(self, pseudo_label_list, max_len): +# res = [] +# assert(max_len >= 2) +# for len in range(2, max_len + 1): +# res += list(product(pseudo_label_list, repeat = len)) +# return res + +# def get_Y(self, X, logic_forward): +# return [logic_forward(nums) for nums in X] + +# def get_candidates(self, key, length = None): +# if key is None: +# return self.get_all_candidates() + +# length = self._length(length) +# return sum([self.base[l][key] for l in length], []) + +# def get_all_candidates(self): +# return sum([sum(v.values(), []) for v in self.base.values()], []) + +# def get_abduce_candidates(self, pred_res, key, length, dist_func, max_address_num, require_more_address): +# if key is None: +# return self.get_all_candidates() + +# candidates = [] +# # all_candidates = list(product(self.pseudo_label_list, repeat = len(pred_res))) + +# for address_num in range(length + 1): +# if(address_num > max_address_num): +# print('No candidates found') +# return None, None, None + +# if(address_num == 0): +# if(self.logic_forward(pred_res) == key): +# candidates.append(pred_res) +# else: +# all_address_candidate = list(product(self.pseudo_label_list, repeat = address_num)) +# address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) +# for address_idx in address_idx_list: +# for c in all_address_candidate: +# pred_res_array = np.array(pred_res) +# pred_res_array[np.array(address_idx)] = c +# if(np.count_nonzero(np.array(c) != np.array(pred_res)[np.array(address_idx)]) == address_num and self.logic_forward(pred_res_array) == key): +# candidates.append(pred_res_array) + +# if(len(candidates) > 0): +# min_address_num = address_num +# break + +# for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): +# if(address_num > max_address_num): +# return candidates, min_address_num, address_num - 1 +# all_candidate = list(product(self.pseudo_label_list, repeat = address_num)) +# address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) +# for address_idx in address_idx_list: +# for c in all_candidate: +# pred_res_array = np.array(pred_res) +# pred_res_array[np.array(address_idx)] = c +# if(np.count_nonzero(np.array(c) != pred_res_array[np.array(address_idx)]) == address_num and self.logic_forward(pred_res_array) == key): +# candidates.append(pred_res_array) + +# return candidates, min_address_num, address_num + + +# def _dict_len(self, dic): +# return sum(len(c) for c in dic.values()) + +# def __len__(self): +# return sum(self._dict_len(v) for v in self.base.values()) class cls_KB(KBBase): def __init__(self, X, Y = None): From 7f07c781d00e8e395077a44588df469baabcaa5d Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 15 Nov 2022 20:24:25 +0800 Subject: [PATCH 007/601] Create kb.py --- abducer/kb.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index c3ddff0..9c09765 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -99,10 +99,11 @@ class add_KB(KBBase): address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) for address_idx in address_idx_list: for c in all_address_candidate: - pred_res_array = np.array(pred_res) - pred_res_array[np.array(address_idx)] = c - if(np.count_nonzero(np.array(c) != np.array(pred_res)[np.array(address_idx)]) == address_num and self.logic_forward(pred_res_array) == key): - candidates.append(pred_res_array) + if(np.count_nonzero(np.array(c) != np.array(pred_res)[np.array(address_idx)]) == address_num): + pred_res_array = np.array(pred_res) + pred_res_array[np.array(address_idx)] = c + if(self.logic_forward(pred_res_array) == key): + candidates.append(pred_res_array) if(len(candidates) > 0): min_address_num = address_num @@ -115,10 +116,11 @@ class add_KB(KBBase): address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) for address_idx in address_idx_list: for c in all_candidate: - pred_res_array = np.array(pred_res) - pred_res_array[np.array(address_idx)] = c - if(np.count_nonzero(np.array(c) != pred_res_array[np.array(address_idx)]) == address_num and self.logic_forward(pred_res_array) == key): - candidates.append(pred_res_array) + if(np.count_nonzero(np.array(c) != np.array(pred_res)[np.array(address_idx)]) == address_num): + pred_res_array = np.array(pred_res) + pred_res_array[np.array(address_idx)] = c + if(self.logic_forward(pred_res_array) == key): + candidates.append(pred_res_array) return candidates, min_address_num, address_num @@ -310,10 +312,16 @@ if __name__ == "__main__": print(res) print() + pseudo_label_list = list(range(10)) + ['+', '-', '*', '/'] + kb = hwf_KB(pseudo_label_list, max_len = 5) + print('len(kb):', len(kb)) + print() + + X = ["1+1", "0+1", "1+0", "2+0", "1+0+1"] Y = [2, 1, 1, 2, 2] kb = cls_KB(X, Y) - print(len(kb)) + print('len(kb):', len(kb)) res = kb.get_candidates(2, 5) print(res) res = kb.get_candidates(2, 3) @@ -325,7 +333,7 @@ if __name__ == "__main__": X = ["1+1", "0+1", "1+0", "2+0", "1+0.5", "0.75+0.75"] Y = [2, 1, 1, 2, 1.5, 1.5] kb = reg_KB(X, Y) - print(len(kb)) + print('len(kb):', len(kb)) res = kb.get_candidates(1.6) print(res) res = kb.get_candidates(1.6, length = 9) From db7244d2be0a7b31e7c4cdfb07e3acf7e88b31e6 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 15 Nov 2022 20:25:54 +0800 Subject: [PATCH 008/601] Update kb.py --- abducer/kb.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 9c09765..b60f50e 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -99,8 +99,8 @@ class add_KB(KBBase): address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) for address_idx in address_idx_list: for c in all_address_candidate: - if(np.count_nonzero(np.array(c) != np.array(pred_res)[np.array(address_idx)]) == address_num): - pred_res_array = np.array(pred_res) + pred_res_array = np.array(pred_res) + if(np.count_nonzero(np.array(c) != pred_res_array[np.array(address_idx)]) == address_num): pred_res_array[np.array(address_idx)] = c if(self.logic_forward(pred_res_array) == key): candidates.append(pred_res_array) @@ -116,8 +116,8 @@ class add_KB(KBBase): address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) for address_idx in address_idx_list: for c in all_candidate: - if(np.count_nonzero(np.array(c) != np.array(pred_res)[np.array(address_idx)]) == address_num): - pred_res_array = np.array(pred_res) + pred_res_array = np.array(pred_res) + if(np.count_nonzero(np.array(c) != pred_res_array[np.array(address_idx)]) == address_num): pred_res_array[np.array(address_idx)] = c if(self.logic_forward(pred_res_array) == key): candidates.append(pred_res_array) From 5beb068ee1c3d9f902fcefc27a1dcf93402b6b28 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 15 Nov 2022 21:23:00 +0800 Subject: [PATCH 009/601] Update kb.py --- abducer/kb.py | 156 +++++++++++++++----------------------------------- 1 file changed, 46 insertions(+), 110 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index b60f50e..95e9692 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -16,8 +16,7 @@ import copy import numpy as np from collections import defaultdict - -from itertools import product, combinations +from itertools import product class KBBase(ABC): def __init__(self): @@ -46,16 +45,17 @@ class KBBase(ABC): pass class add_KB(KBBase): - def __init__(self, pseudo_label_list, max_len = 5): + def __init__(self, pseudo_label_list, kb_max_len = -1): super().__init__() self.pseudo_label_list = pseudo_label_list self.base = {} - - X = self.get_X(self.pseudo_label_list, max_len) - Y = self.get_Y(X, self.logic_forward) + self.kb_max_len = kb_max_len + if(self.kb_max_len > 0): + X = self.get_X(self.pseudo_label_list, self.kb_max_len) + Y = self.get_Y(X, self.logic_forward) - for x, y in zip(X, Y): - self.base.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) + for x, y in zip(X, Y): + self.base.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) def logic_forward(self, nums): return sum(nums) @@ -71,60 +71,20 @@ class add_KB(KBBase): return [logic_forward(nums) for nums in X] def get_candidates(self, key, length = None): + if(self.base == {}): + return [] + if key is None: return self.get_all_candidates() length = self._length(length) + if(self.kb_max_len < min(length)): + return [] return sum([self.base[l][key] for l in length], []) def get_all_candidates(self): return sum([sum(v.values(), []) for v in self.base.values()], []) - def get_abduce_candidates(self, pred_res, key, max_address_num, require_more_address): - if key is None: - return self.get_all_candidates() - - candidates = [] - - for address_num in range(len(pred_res) + 1): - if(address_num > max_address_num): - print('No candidates found') - return None, None, None - - if(address_num == 0): - if(self.logic_forward(pred_res) == key): - candidates.append(pred_res) - else: - all_address_candidate = list(product(self.pseudo_label_list, repeat = address_num)) - address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) - for address_idx in address_idx_list: - for c in all_address_candidate: - pred_res_array = np.array(pred_res) - if(np.count_nonzero(np.array(c) != pred_res_array[np.array(address_idx)]) == address_num): - pred_res_array[np.array(address_idx)] = c - if(self.logic_forward(pred_res_array) == key): - candidates.append(pred_res_array) - - if(len(candidates) > 0): - min_address_num = address_num - break - - for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): - if(address_num > max_address_num): - return candidates, min_address_num, address_num - 1 - all_candidate = list(product(self.pseudo_label_list, repeat = address_num)) - address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) - for address_idx in address_idx_list: - for c in all_candidate: - pred_res_array = np.array(pred_res) - if(np.count_nonzero(np.array(c) != pred_res_array[np.array(address_idx)]) == address_num): - pred_res_array[np.array(address_idx)] = c - if(self.logic_forward(pred_res_array) == key): - candidates.append(pred_res_array) - - return candidates, min_address_num, address_num - - def _dict_len(self, dic): return sum(len(c) for c in dic.values()) @@ -132,16 +92,17 @@ class add_KB(KBBase): return sum(self._dict_len(v) for v in self.base.values()) # class hwf_KB(KBBase): -# def __init__(self, pseudo_label_list, max_len = 5): +# def __init__(self, pseudo_label_list, kb_max_len = -1): # super().__init__() # self.pseudo_label_list = pseudo_label_list # self.base = {} - -# X = self.get_X(self.pseudo_label_list, max_len) -# Y = self.get_Y(X, self.logic_forward) +# self.kb_max_len = kb_max_len +# if(self.kb_max_len > 0): +# X = self.get_X(self.pseudo_label_list, self.kb_max_len) +# Y = self.get_Y(X, self.logic_forward) -# for x, y in zip(X, Y): -# self.base.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) +# for x, y in zip(X, Y): +# self.base.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) # def logic_forward(self, nums): # return sum(nums) @@ -157,65 +118,26 @@ class add_KB(KBBase): # return [logic_forward(nums) for nums in X] # def get_candidates(self, key, length = None): +# if(self.base == {}): +# return [] + # if key is None: # return self.get_all_candidates() # length = self._length(length) +# if(self.kb_max_len < min(length)): +# return [] # return sum([self.base[l][key] for l in length], []) # def get_all_candidates(self): # return sum([sum(v.values(), []) for v in self.base.values()], []) - -# def get_abduce_candidates(self, pred_res, key, length, dist_func, max_address_num, require_more_address): -# if key is None: -# return self.get_all_candidates() - -# candidates = [] -# # all_candidates = list(product(self.pseudo_label_list, repeat = len(pred_res))) - -# for address_num in range(length + 1): -# if(address_num > max_address_num): -# print('No candidates found') -# return None, None, None - -# if(address_num == 0): -# if(self.logic_forward(pred_res) == key): -# candidates.append(pred_res) -# else: -# all_address_candidate = list(product(self.pseudo_label_list, repeat = address_num)) -# address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) -# for address_idx in address_idx_list: -# for c in all_address_candidate: -# pred_res_array = np.array(pred_res) -# pred_res_array[np.array(address_idx)] = c -# if(np.count_nonzero(np.array(c) != np.array(pred_res)[np.array(address_idx)]) == address_num and self.logic_forward(pred_res_array) == key): -# candidates.append(pred_res_array) - -# if(len(candidates) > 0): -# min_address_num = address_num -# break - -# for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): -# if(address_num > max_address_num): -# return candidates, min_address_num, address_num - 1 -# all_candidate = list(product(self.pseudo_label_list, repeat = address_num)) -# address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) -# for address_idx in address_idx_list: -# for c in all_candidate: -# pred_res_array = np.array(pred_res) -# pred_res_array[np.array(address_idx)] = c -# if(np.count_nonzero(np.array(c) != pred_res_array[np.array(address_idx)]) == address_num and self.logic_forward(pred_res_array) == key): -# candidates.append(pred_res_array) - -# return candidates, min_address_num, address_num - # def _dict_len(self, dic): # return sum(len(c) for c in dic.values()) # def __len__(self): # return sum(self._dict_len(v) for v in self.base.values()) - + class cls_KB(KBBase): def __init__(self, X, Y = None): super().__init__() @@ -298,25 +220,39 @@ class reg_KB(KBBase): return sum([sum(len(x) for x in D[0]) for D in self.base.values()]) if __name__ == "__main__": + # With ground KB pseudo_label_list = list(range(10)) - kb = add_KB(pseudo_label_list, max_len = 5) + kb = add_KB(pseudo_label_list, kb_max_len = 5) print('len(kb):', len(kb)) - print() res = kb.get_candidates(0) print(res) - print() res = kb.get_candidates(18, length = 2) print(res) - print() + res = kb.get_candidates(18, length = 8) + print(res) res = kb.get_candidates(7, length = 3) print(res) print() - pseudo_label_list = list(range(10)) + ['+', '-', '*', '/'] - kb = hwf_KB(pseudo_label_list, max_len = 5) + # Without ground KB + pseudo_label_list = list(range(10)) + kb = add_KB(pseudo_label_list) print('len(kb):', len(kb)) + res = kb.get_candidates(0) + print(res) + res = kb.get_candidates(18, length = 2) + print(res) + res = kb.get_candidates(18, length = 8) + print(res) + res = kb.get_candidates(7, length = 3) + print(res) print() + # pseudo_label_list = list(range(10)) + ['+', '-', '*', '/'] + # kb = hwf_KB(pseudo_label_list, max_len = 5) + # print('len(kb):', len(kb)) + # print() + X = ["1+1", "0+1", "1+0", "2+0", "1+0+1"] Y = [2, 1, 1, 2, 2] From 7edd652eea43fb43824db61b7bf1929fc0b12779 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 15 Nov 2022 21:23:15 +0800 Subject: [PATCH 010/601] Update abducer_base.py --- abducer/abducer_base.py | 77 +++++++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 15 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index f990013..b1c661b 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -14,15 +14,14 @@ import abc from kb import add_KB import numpy as np -def hamming_dist(A, B): - return np.sum(np.array(A) != np.array(B)) +from itertools import product, combinations -def hamming_dist_kb(A, B): +def hamming_dist(A, B): B = np.array(B) A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) return np.sum(A != B, axis = 1) -def confidence_dist_kb(A, B): +def confidence_dist(A, B): B = np.array(B) #print(A) @@ -41,7 +40,10 @@ class AbducerBase(abc.ABC): def __init__(self, kb, dist_func = "hamming", pred_res_parse = None, cache = True): self.kb = kb if dist_func == "hamming": - self.dist_func = hamming_dist + dist_func = hamming_dist + elif dist_func == "confidence": + dist_func = confidence_dist + self.dist_func = dist_func if pred_res_parse is None: pred_res_parse = lambda x : x["cls"] self.pred_res_parse = pred_res_parse @@ -50,6 +52,7 @@ class AbducerBase(abc.ABC): self.cache_min_address_num = {} self.cache_candidates = {} + def abduce(self, data, max_address_num = 3, require_more_address = 0, length = -1): pred_res, ans = data @@ -62,8 +65,16 @@ class AbducerBase(abc.ABC): print('cached') return self.cache_candidates[(tuple(pred_res), ans, address_num)] - - candidates, min_address_num, address_num = self.kb.get_abduce_candidates(pred_res, ans, length, self.dist_func, max_address_num, require_more_address) + if(self.kb.base != {}): + all_candidates = self.kb.get_candidates(ans, length) + cost_list = self.dist_func(pred_res, all_candidates) + min_address_num = np.min(cost_list) + address_num = min(max_address_num, min_address_num + require_more_address) + idxs = np.where(cost_list <= address_num)[0] + candidates = [all_candidates[idx] for idx in idxs] + + else: + candidates, min_address_num, address_num = self.get_abduce_candidates(pred_res, ans, max_address_num, require_more_address) if(self.cache): self.cache_min_address_num[(tuple(pred_res), ans)] = min_address_num @@ -71,21 +82,57 @@ class AbducerBase(abc.ABC): return candidates - # candidates = self.kb.get_candidates(ans, length) - # cost_list = self.dist_func(pred_res, candidates) - # address_num = np.min(cost_list) - # # threshold = min(address_num + require_more_address, max_address_num) - # idxs = np.where(cost_list <= address_num + require_more_address)[0] - - # return [candidates[idx] for idx in idxs], address_num # if len(idxs) > 1: # return None # return [candidates[idx] for idx in idxs] + + def address(self, address_num, pred_res, key): + new_candidates = [] + all_address_candidate = list(product(self.kb.pseudo_label_list, repeat = address_num)) + address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) + for address_idx in address_idx_list: + for c in all_address_candidate: + pred_res_array = np.array(pred_res) + if(np.count_nonzero(np.array(c) != pred_res_array[np.array(address_idx)]) == address_num): + pred_res_array[np.array(address_idx)] = c + if(self.kb.logic_forward(pred_res_array) == key): + new_candidates.append(pred_res_array) + return new_candidates, address_num + + def get_abduce_candidates(self, pred_res, key, max_address_num, require_more_address): + + candidates = [] + for address_num in range(len(pred_res) + 1): + if(address_num > max_address_num): + print('No candidates found') + return None, None, None + + if(address_num == 0): + if(self.kb.logic_forward(pred_res) == key): + candidates.append(pred_res) + else: + new_candidates, address_num = self.address(address_num, pred_res, key) + candidates += new_candidates + + if(len(candidates) > 0): + min_address_num = address_num + break + + for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): + if(address_num > max_address_num): + return candidates, min_address_num, address_num - 1 + new_candidates, address_num = self.address(address_num, pred_res, key) + candidates += new_candidates + + return candidates, min_address_num, address_num + + + def batch_abduce(self, Y, C, max_address_num = 3, require_more_address = 0): return [ self.abduce((y, c), max_address_num, require_more_address)\ @@ -101,7 +148,7 @@ if __name__ == "__main__": pseudo_label_list = list(range(10)) kb = add_KB(pseudo_label_list) abd = AbducerBase(kb) - res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 0) + res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 1) print(res) print() res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 1) From 0883e27fc197609601fcf5a06da8ca17a1c773eb Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 15 Nov 2022 22:50:07 +0800 Subject: [PATCH 011/601] Update abducer_base.py --- abducer/abducer_base.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index b1c661b..38cbf64 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -45,7 +45,10 @@ class AbducerBase(abc.ABC): dist_func = confidence_dist self.dist_func = dist_func if pred_res_parse is None: - pred_res_parse = lambda x : x["cls"] + if(dist_func == "hamming"): + pred_res_parse = lambda x : x["cls"] + elif dist_func == "confidence": + pred_res_parse = lambda x : x[" "] self.pred_res_parse = pred_res_parse self.cache = cache @@ -75,20 +78,18 @@ class AbducerBase(abc.ABC): else: candidates, min_address_num, address_num = self.get_abduce_candidates(pred_res, ans, max_address_num, require_more_address) + cost_list = self.dist_func(pred_res, candidates) if(self.cache): self.cache_min_address_num[(tuple(pred_res), ans)] = min_address_num self.cache_candidates[(tuple(pred_res), ans, address_num)] = candidates - - return candidates - + cost_list = self.dist_func(pred_res, candidates) + min_address_num = np.min(cost_list) + idxs = np.where(cost_list == min_address_num)[0] + candidates = [candidates[idx] for idx in idxs] - - - # if len(idxs) > 1: - # return None - # return [candidates[idx] for idx in idxs] + return candidates[0] def address(self, address_num, pred_res, key): new_candidates = [] @@ -99,7 +100,7 @@ class AbducerBase(abc.ABC): pred_res_array = np.array(pred_res) if(np.count_nonzero(np.array(c) != pred_res_array[np.array(address_idx)]) == address_num): pred_res_array[np.array(address_idx)] = c - if(self.kb.logic_forward(pred_res_array) == key): + if(abs(self.kb.logic_forward(pred_res_array) - key) <= 1e-3): new_candidates.append(pred_res_array) return new_candidates, address_num @@ -113,7 +114,7 @@ class AbducerBase(abc.ABC): return None, None, None if(address_num == 0): - if(self.kb.logic_forward(pred_res) == key): + if(abs(self.kb.logic_forward(pred_res) - key) <= 1e-3): candidates.append(pred_res) else: new_candidates, address_num = self.address(address_num, pred_res, key) @@ -148,7 +149,7 @@ if __name__ == "__main__": pseudo_label_list = list(range(10)) kb = add_KB(pseudo_label_list) abd = AbducerBase(kb) - res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 1) + res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 0) print(res) print() res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 1) From 7f29b79aeeb7982410fbc9aafc7e3b090524c7ce Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Tue, 15 Nov 2022 23:25:17 +0800 Subject: [PATCH 012/601] modify wabl_models.py and basic_model.py --- models/basic_model.py | 139 +++++++++++++++++++++++------------------- models/lenet5.py | 2 +- models/wabl_models.py | 62 ++++++------------- 3 files changed, 94 insertions(+), 109 deletions(-) diff --git a/models/basic_model.py b/models/basic_model.py index c54bb22..47aeab9 100644 --- a/models/basic_model.py +++ b/models/basic_model.py @@ -18,8 +18,6 @@ from torch.autograd import Variable from torch.utils.data import Dataset import torchvision -import utils.utils as mutils - import os from multiprocessing import Pool @@ -121,6 +119,7 @@ class FakeRecorder(): from torch.nn import init from torch import nn + def weigth_init(m): if isinstance(m, nn.Conv2d): init.xavier_uniform_(m.weight.data) @@ -137,18 +136,23 @@ class BasicModel(): model, criterion, optimizer, - converter, device, params, sign_list, + transform = None, + target_transform=None, + collate_fn = None, + pretrained = False, recorder = None): self.model = model.to(device) - self.model.apply(weigth_init) + self.criterion = criterion self.optimizer = optimizer - self.converter = converter + self.transform = transform + self.target_transform = target_transform self.device = device + sign_list = sorted(list(set(sign_list))) self.mapping = dict(zip(sign_list, list(range(len(sign_list))))) self.remapping = dict(zip(list(range(len(sign_list))), sign_list)) @@ -157,8 +161,15 @@ class BasicModel(): recorder = FakeRecorder() self.recorder = recorder + if pretrained: + # the paths of model, optimizer should be included in params + self.load(params.load_dir) + else: + self.model.apply(weigth_init) + self.save_interval = params.saveInterval self.params = params + self.collate_fn = collate_fn pass def _fit(self, data_loader, n_epoch, stop_loss): @@ -171,7 +182,10 @@ class BasicModel(): recorder.print(f"{epoch}/{n_epoch} model training loss is {loss_value}") if loss_value < min_loss: min_loss = loss_value - if loss_value < stop_loss: + if epoch > 0 and self.save_interval is not None and epoch % self.save_interval == 0: + assert hasattr(self.params, 'save_dir') + self.save(self.params.save_dir) + if stop_loss is not None and loss_value < stop_loss: break recorder.print("Model fitted, minimal loss is ", min_loss) return loss_value @@ -181,30 +195,32 @@ class BasicModel(): def fit(self, data_loader = None, X = None, - y = None, - n_epoch = 100, - stop_loss = 0.001): + y = None): if data_loader is None: params = self.params + collate_fn = self.collate_fn + transform = self.transform + target_transform = self.target_transform + Y = self.str2ints(y) - train_dataset = XYDataset(X, Y) + train_dataset = XYDataset(X, Y, transform=transform, target_transform=target_transform) sampler = None data_loader = torch.utils.data.DataLoader(train_dataset, batch_size=params.batchSize, \ shuffle=True, sampler=sampler, num_workers=int(params.workers), \ - collate_fn=alignCollate(imgH=params.imgH, imgW=params.imgW, keep_ratio=params.keep_ratio)) - return self._fit(data_loader, n_epoch, stop_loss) + collate_fn=collate_fn) + return self._fit(data_loader, params.n_epoch, params.stop_loss) def train_epoch(self, data_loader): - loss_avg = mutils.averager() + # loss_avg = mutils.averager() + self.model.train() + loss_value = 0 for i, data in enumerate(data_loader): X = data[0] Y = data[1] - cost = self.train_batch(X, Y) - loss_avg.add(cost) - - loss_value = float(loss_avg.val()) - loss_avg.reset() + loss = self.train_batch(X, Y) + loss_value += loss.item() + return loss_value def train_batch(self, X, Y): @@ -212,17 +228,10 @@ class BasicModel(): model = self.model criterion = self.criterion optimizer = self.optimizer - converter = self.converter device = self.device - - # set training mode - for p in model.parameters(): - p.requires_grad = True - model.train() # init training status - torch.autograd.set_detect_anomaly(True) - optimizer.zero_grad() + # torch.autograd.set_detect_anomaly(True) # model predict X = X.to(device) @@ -233,41 +242,39 @@ class BasicModel(): loss = criterion(pred_Y, Y) # back propagation and optimize + optimizer.zero_grad() loss.backward() optimizer.step() return loss def _predict(self, data_loader): model = self.model - criterion = self.criterion - converter = self.converter - params = self.params device = self.device - - for p in model.parameters(): - p.requires_grad = False model.eval() - - n_correct = 0 - - results = [] - for i, data in enumerate(data_loader): - X = data[0].to(device) - pred_Y = model(X) - results.append(pred_Y) + + with torch.no_grad(): + results = [] + for i, data in enumerate(data_loader): + X = data[0].to(device) + pred_Y = model(X) + results.append(pred_Y) return torch.cat(results, axis=0) def predict(self, data_loader = None, X = None, print_prefix = ""): - params = self.params if data_loader is None: + params = self.params + collate_fn = self.collate_fn + transform = self.transform + target_transform = self.target_transform + Y = [0] * len(X) - val_dataset = XYDataset(X, Y) + val_dataset = XYDataset(X, Y, transform=transform, target_transform=target_transform) sampler = None data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=params.batchSize, \ shuffle=False, sampler=sampler, num_workers=int(params.workers), \ - collate_fn=alignCollate(imgH=params.imgH, imgW=params.imgW, keep_ratio=params.keep_ratio)) + collate_fn=collate_fn) recorder = self.recorder recorder.print('Start Predict ', print_prefix) @@ -275,14 +282,18 @@ class BasicModel(): return [self.remapping[int(y)] for y in Y] def predict_proba(self, data_loader = None, X = None, print_prefix = ""): - params = self.params if data_loader is None: + params = self.params + collate_fn = self.collate_fn + transform = self.transform + target_transform = self.target_transform + Y = [0] * len(X) - val_dataset = XYDataset(X, Y) + val_dataset = XYDataset(X, Y, transform=transform, target_transform=target_transform) sampler = None data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=params.batchSize, \ shuffle=False, sampler=sampler, num_workers=int(params.workers), \ - collate_fn=alignCollate(imgH=params.imgH, imgW=params.imgW, keep_ratio=params.keep_ratio)) + collate_fn=collate_fn) recorder = self.recorder recorder.print('Start Predict ', print_prefix) @@ -292,45 +303,45 @@ class BasicModel(): model = self.model criterion = self.criterion recorder = self.recorder - converter = self.converter - params = self.params device = self.device recorder.print('Start val ', print_prefix) - - for p in model.parameters(): - p.requires_grad = False model.eval() n_correct = 0 pred_num = 0 - loss_avg = mutils.averager() - for i, data in enumerate(data_loader): - X = data[0].to(device) - Y = data[1].to(device) + loss_value = 0 + with torch.no_grad(): + for i, data in enumerate(data_loader): + X = data[0].to(device) + Y = data[1].to(device) - pred_Y = model(X) + pred_Y = model(X) - correct_num = sum(Y == pred_Y.argmax(axis=1)) - loss = criterion(pred_Y, Y) - loss_avg.add(loss) + correct_num = sum(Y == pred_Y.argmax(axis=1)) + loss = criterion(pred_Y, Y) + loss_value += loss.item() n_correct += correct_num pred_num += len(X) accuracy = float(n_correct) / float(pred_num) - recorder.print('[%s] Val loss: %f, accuray: %f' % (print_prefix, loss_avg.val(), accuracy)) + recorder.print('[%s] Val loss: %f, accuray: %f' % (print_prefix, loss_value, accuracy)) return accuracy def val(self, data_loader = None, X = None, y = None, print_prefix = ""): - params = self.params if data_loader is None: - y = self.str2ints(y) - val_dataset = XYDataset(X, y) + params = self.params + collate_fn = self.collate_fn + transform = self.transform + target_transform = self.target_transform + + Y = self.str2ints(y) + val_dataset = XYDataset(X, Y, transform=transform, target_transform=target_transform) sampler = None data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=params.batchSize, \ shuffle=True, sampler=sampler, num_workers=int(params.workers), \ - collate_fn=alignCollate(imgH=params.imgH, imgW=params.imgW, keep_ratio=params.keep_ratio)) + collate_fn=collate_fn) return self._val(data_loader, print_prefix) def score(self, data_loader = None, X = None, y = None, print_prefix = ""): diff --git a/models/lenet5.py b/models/lenet5.py index 676f553..9d5b054 100644 --- a/models/lenet5.py +++ b/models/lenet5.py @@ -34,7 +34,7 @@ class LeNet5(nn.Module): self.fc1 = nn.Linear(256, 120) self.fc2 = nn.Linear(120, 84) - self.fc3 = nn.Linear(84, 13) + self.fc3 = nn.Linear(84, 10) def forward(self, x): '''å‰å‘传播函数''' diff --git a/models/wabl_models.py b/models/wabl_models.py index 4b27418..15fe6e6 100644 --- a/models/wabl_models.py +++ b/models/wabl_models.py @@ -21,6 +21,7 @@ from sklearn.preprocessing import StandardScaler from sklearn.svm import SVC from sklearn.gaussian_process import GaussianProcessClassifier from sklearn.gaussian_process.kernels import RBF +from models.basic_model import BasicModel import pickle as pk import random @@ -36,7 +37,6 @@ def merge_data(X): ret_X = list(chain(*X)) return ret_X, ret_mark - def reshape_data(Y, marks): begin_mark = 0 ret_Y = [] @@ -58,57 +58,26 @@ class WABLBasicModel: pass def predict(self, X): - if self.share: - data_X, marks = merge_data(X) - prob = self.cls_list[0].predict_proba(X = data_X) - cls = np.array(prob).argmax(axis = 1) + data_X, marks = merge_data(X) + prob = self.cls_list[0].predict_proba(X = data_X) + cls = np.array(prob).argmax(axis = 1) - prob = reshape_data(prob, marks) - cls = reshape_data(cls, marks) - else: - cls_result = [] - prob_result = [] - for i in range(self.code_len): - data_X = get_part_data(X, i) - tmp_prob = self.cls_list[i].predict_proba(X = data_X) - cls_result.append(np.array(tmp_prob).argmax(axis = 1)) - prob_result.append(tmp_prob) - - cls = list(zip(*cls_result)) - prob = list(zip(*prob_result)) + prob = reshape_data(prob, marks) + cls = reshape_data(cls, marks) return {"cls" : cls, "prob" : prob} def valid(self, X, Y): - if self.share: - data_X, _ = merge_data(X) - data_Y, _ = merge_data(Y) - score = self.cls_list[0].score(X = data_X, y = data_Y) - return score, [score] - else: - score_list = [] - for i in range(self.code_len): - data_X = get_part_data(X, i) - data_Y = get_part_data(Y, i) - score_list.append(self.cls_list[i].score(data_X, data_Y)) - - return sum(score_list) / len(score_list), score_list + data_X, _ = merge_data(X) + data_Y, _ = merge_data(Y) + score = self.cls_list[0].score(X = data_X, y = data_Y) + return score, [score] def train(self, X, Y): #self.label_lists = [] - if self.share: - data_X, _ = merge_data(X) - data_Y, _ = merge_data(Y) - self.cls_list[0].fit(X = data_X, y = data_Y) - else: - for i in range(self.code_len): - data_X = get_part_data(X, i) - data_Y = get_part_data(Y, i) - self.cls_list[i].fit(data_X, data_Y) - - def _set_label_lists(self, label_lists): - label_lists = [sorted(list(set(label_list))) for label_list in label_lists] - self.label_lists = label_lists + data_X, _ = merge_data(X) + data_Y, _ = merge_data(Y) + self.cls_list[0].fit(X = data_X, y = data_Y) class DecisionTree(WABLBasicModel): def __init__(self, code_len, label_lists, share = False): @@ -169,6 +138,11 @@ class CNN(WABLBasicModel): self.cls_list[i].fit(data_X, data_Y) #self.label_lists.append(sorted(list(set(data_Y)))) +class MyModel(WABLBasicModel): + def __init__(self, base_model): + + self.cls_list = [] + self.cls_list.append(base_model) if __name__ == "__main__": #data_path = "utils/hamming_data/generated_data/hamming_7_3_0.20.pk" From 6ffdf44c351c31ea0692688f0efdb0eafb9b92f1 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 16 Nov 2022 10:16:13 +0800 Subject: [PATCH 013/601] Update kb.py --- abducer/kb.py | 158 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 115 insertions(+), 43 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 95e9692..6007a5b 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -91,52 +91,120 @@ class add_KB(KBBase): def __len__(self): return sum(self._dict_len(v) for v in self.base.values()) -# class hwf_KB(KBBase): -# def __init__(self, pseudo_label_list, kb_max_len = -1): -# super().__init__() -# self.pseudo_label_list = pseudo_label_list -# self.base = {} -# self.kb_max_len = kb_max_len -# if(self.kb_max_len > 0): -# X = self.get_X(self.pseudo_label_list, self.kb_max_len) -# Y = self.get_Y(X, self.logic_forward) - -# for x, y in zip(X, Y): -# self.base.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) +class hwf_KB(KBBase): + def __init__(self, pseudo_label_list, kb_max_len = -1): + super().__init__() + self.pseudo_label_list = pseudo_label_list + self.base = {} + self.kb_max_len = kb_max_len + if(self.kb_max_len > 0): + X = self.get_X(self.pseudo_label_list, self.kb_max_len) + Y = self.get_Y(X, self.logic_forward) + + for x, y in zip(X, Y): + self.base.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) -# def logic_forward(self, nums): -# return sum(nums) + def calculate(self, formula): + stack = [] + postfix = [] + priority = {'+': 0, '-': 0, + '*': 1, '/': 1} + skip_flag = 0 + for i in range(len(formula)): + if formula[i] == '-': + if i == 0: + formula.insert(0, 0) + for i in range(len(formula)): + if skip_flag: + skip_flag -= 1 + continue + char = formula[i] + if char in priority.keys(): + while stack and (priority[char] <= priority[stack[-1]]): + postfix.append(stack.pop()) + stack.append(char) + else: + num = char + while (i + 1) < len(formula): + if formula[i + 1] not in priority.keys(): + skip_flag += 1 + num = num * 10 + formula[i + 1] + i += 1 + else: + break + postfix.append(num) + while stack: + postfix.append(stack.pop()) + + for i in postfix: + if i in priority.keys(): + num2 = stack.pop() + num1 = stack.pop() + if i == '+': + res = num1 + num2 + elif i == '-': + res = num1 - num2 + elif i == '*': + res = num1 * num2 + elif i == '/': + if(num2 == 0): + return np.inf + res = num1 / num2 + stack.append(res) + else: + stack.append(i) + return round(stack[0], 2) -# def get_X(self, pseudo_label_list, max_len): -# res = [] -# assert(max_len >= 2) -# for len in range(2, max_len + 1): -# res += list(product(pseudo_label_list, repeat = len)) -# return res - -# def get_Y(self, X, logic_forward): -# return [logic_forward(nums) for nums in X] - -# def get_candidates(self, key, length = None): -# if(self.base == {}): -# return [] + def valid_formula(self, formula): + symbol_idx_list = [] + first_minus_flag = 0 + for idx, c in enumerate(formula): + if(idx == 0 and c == '-'): + first_minus_flag = 1 + continue + if(c in ['+', '-', '*', '/']): + if(idx - 1 in symbol_idx_list or (idx == 1 and first_minus_flag == 1)): + return False + symbol_idx_list.append(idx) + if(0 in symbol_idx_list or len(formula) - 1 in symbol_idx_list): + return False + return True + + def logic_forward(self, formula): + if(self.valid_formula(formula) == False): + return np.inf + return self.calculate(list(formula)) -# if key is None: -# return self.get_all_candidates() + def get_X(self, pseudo_label_list, max_len): + res = [] + assert(max_len >= 2) + for len in range(2, max_len + 1): + res += list(product(pseudo_label_list, repeat = len)) + return res -# length = self._length(length) -# if(self.kb_max_len < min(length)): -# return [] -# return sum([self.base[l][key] for l in length], []) + def get_Y(self, X, logic_forward): + return [logic_forward(formula) for formula in X] + + def get_candidates(self, key, length = None): + if(self.base == {}): + return [] + + if key is None: + return self.get_all_candidates() + + length = self._length(length) + if(self.kb_max_len < min(length)): + return [] + return sum([self.base[l][key] for l in length], []) -# def get_all_candidates(self): -# return sum([sum(v.values(), []) for v in self.base.values()], []) + def get_all_candidates(self): + return sum([sum(v.values(), []) for v in self.base.values()], []) -# def _dict_len(self, dic): -# return sum(len(c) for c in dic.values()) + def _dict_len(self, dic): + return sum(len(c) for c in dic.values()) -# def __len__(self): -# return sum(self._dict_len(v) for v in self.base.values()) + def __len__(self): + return sum(self._dict_len(v) for v in self.base.values()) class cls_KB(KBBase): def __init__(self, X, Y = None): @@ -248,10 +316,14 @@ if __name__ == "__main__": print(res) print() - # pseudo_label_list = list(range(10)) + ['+', '-', '*', '/'] - # kb = hwf_KB(pseudo_label_list, max_len = 5) - # print('len(kb):', len(kb)) - # print() + pseudo_label_list = list(range(10)) + ['+', '-', '*', '/'] + kb = hwf_KB(pseudo_label_list, kb_max_len = 5) + print('len(kb):', len(kb)) + res = kb.get_candidates(1, length = 3) + print(res) + res = kb.get_candidates(3.67, length = 5) + print(res) + print() X = ["1+1", "0+1", "1+0", "2+0", "1+0+1"] From 821c79f44dd4b427b18b1deb8ce029032554c413 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 16 Nov 2022 10:44:30 +0800 Subject: [PATCH 014/601] Update kb.py --- abducer/kb.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 6007a5b..5d25a46 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -124,11 +124,11 @@ class hwf_KB(KBBase): postfix.append(stack.pop()) stack.append(char) else: - num = char + num = int(char) while (i + 1) < len(formula): if formula[i + 1] not in priority.keys(): skip_flag += 1 - num = num * 10 + formula[i + 1] + num = num * 10 + int(formula[i + 1]) i += 1 else: break @@ -316,7 +316,7 @@ if __name__ == "__main__": print(res) print() - pseudo_label_list = list(range(10)) + ['+', '-', '*', '/'] + pseudo_label_list = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '+', '-', '*', '/'] kb = hwf_KB(pseudo_label_list, kb_max_len = 5) print('len(kb):', len(kb)) res = kb.get_candidates(1, length = 3) From 73bb3674e205cdf1e0c0b9a7a1304ee267333a39 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 16 Nov 2022 10:44:46 +0800 Subject: [PATCH 015/601] Update abducer_base.py --- abducer/abducer_base.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 38cbf64..37c4bf8 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -11,7 +11,7 @@ #================================================================# import abc -from kb import add_KB +from kb import add_KB, hwf_KB import numpy as np from itertools import product, combinations @@ -100,7 +100,7 @@ class AbducerBase(abc.ABC): pred_res_array = np.array(pred_res) if(np.count_nonzero(np.array(c) != pred_res_array[np.array(address_idx)]) == address_num): pred_res_array[np.array(address_idx)] = c - if(abs(self.kb.logic_forward(pred_res_array) - key) <= 1e-3): + if(self.kb.logic_forward(pred_res_array) == key): new_candidates.append(pred_res_array) return new_candidates, address_num @@ -151,19 +151,21 @@ if __name__ == "__main__": abd = AbducerBase(kb) res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 0) print(res) - print() res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 1) print(res) - print() res = abd.abduce(([1, 1, 1], 4), max_address_num = 1, require_more_address = 1) print(res) - print() res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 0) print(res) - print() res = abd.abduce(([1, 1, 1], 5), max_address_num = 2, require_more_address = 1) print(res) - # res = abd.abduce(([0, 2, 0], 0.99), 1, 0) - # print(res) - + print() + pseudo_label_list = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '+', '-', '*', '/'] + kb = hwf_KB(pseudo_label_list) + abd = AbducerBase(kb) + res = abd.abduce((['5', '+', '2'], 3), max_address_num = 2, require_more_address = 0) + print(res) + res = abd.abduce((['5', '+', '2'], 1.67), max_address_num = 2, require_more_address = 0) + print(res) + print() From 5efe40fc637780c7d96c58dcbdcfc19e52097bc7 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 16 Nov 2022 10:59:13 +0800 Subject: [PATCH 016/601] Update abducer_base.py --- abducer/abducer_base.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 37c4bf8..576cce4 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -55,6 +55,11 @@ class AbducerBase(abc.ABC): self.cache_min_address_num = {} self.cache_candidates = {} + def get_min_cost_candidate(self, pred_res, candidates): + cost_list = self.dist_func(pred_res, candidates) + min_address_num = np.min(cost_list) + idxs = np.where(cost_list == min_address_num)[0] + return [candidates[idx] for idx in idxs][0] def abduce(self, data, max_address_num = 3, require_more_address = 0, length = -1): pred_res, ans = data @@ -78,18 +83,13 @@ class AbducerBase(abc.ABC): else: candidates, min_address_num, address_num = self.get_abduce_candidates(pred_res, ans, max_address_num, require_more_address) - cost_list = self.dist_func(pred_res, candidates) if(self.cache): self.cache_min_address_num[(tuple(pred_res), ans)] = min_address_num self.cache_candidates[(tuple(pred_res), ans, address_num)] = candidates - - cost_list = self.dist_func(pred_res, candidates) - min_address_num = np.min(cost_list) - idxs = np.where(cost_list == min_address_num)[0] - candidates = [candidates[idx] for idx in idxs] - - return candidates[0] + + candidates = self.get_min_cost_candidate(pred_res, candidates) + return candidates def address(self, address_num, pred_res, key): new_candidates = [] @@ -168,4 +168,6 @@ if __name__ == "__main__": print(res) res = abd.abduce((['5', '+', '2'], 1.67), max_address_num = 2, require_more_address = 0) print(res) + res = abd.abduce((['5', '+', '3'], 0.33), max_address_num = 3, require_more_address = 3) + print(res) print() From 8b5a2ce2a53cbb2bda24817266ded05434927f7d Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 16 Nov 2022 13:07:03 +0800 Subject: [PATCH 017/601] Update get_mnist_add.py --- datasets/mnist_add/get_mnist_add.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/datasets/mnist_add/get_mnist_add.py b/datasets/mnist_add/get_mnist_add.py index 167ee57..0c9a273 100644 --- a/datasets/mnist_add/get_mnist_add.py +++ b/datasets/mnist_add/get_mnist_add.py @@ -5,20 +5,28 @@ from torchvision.transforms import transforms def get_mnist_add(): transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081, ))]) - train_dataset = torchvision.datasets.MNIST(root='./', train=True, download=True, transform=transform) - test_loader = torch.utils.data.DataLoader(torchvision.datasets.MNIST('./', train=False, transform=transform), batch_size=1000, shuffle=True) + img_dataset = torchvision.datasets.MNIST(root='./', train=True, download=True, transform=transform) - X = [] - Y = [] + train_X = [] + train_Y = [] with open('./train_data.txt') as f: for line in f: line = line.strip().split(' ') - X.append((train_dataset[int(line[0])][0], train_dataset[int(line[1])][0])) - Y.append(int(line[2])) + train_X.append((img_dataset[int(line[0])][0], img_dataset[int(line[1])][0])) + train_Y.append(int(line[2])) - return X, Y, test_loader + test_X = [] + test_Y = [] + with open('./test_data.txt') as f: + for line in f: + line = line.strip().split(' ') + test_X.append((img_dataset[int(line[0])][0], img_dataset[int(line[1])][0])) + test_Y.append(int(line[2])) + + return train_X, train_Y, test_X, test_Y if __name__ == "__main__": - X, Y, test_loader = get_mnist_add() - print(len(X), len(Y)) - print(X[0][0].shape, X[0][1].shape, Y[0]) + train_X, train_Y, test_X, test_Y = get_mnist_add() + print(len(train_X), len(test_X)) + print(train_X[0][0].shape, train_X[0][1].shape, train_Y[0]) + From 4fa2f8594555aa6091b56f9b73a270583839acae Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 16 Nov 2022 13:09:47 +0800 Subject: [PATCH 018/601] Update get_mnist_add.py --- datasets/mnist_add/get_mnist_add.py | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/datasets/mnist_add/get_mnist_add.py b/datasets/mnist_add/get_mnist_add.py index 0c9a273..183f9a5 100644 --- a/datasets/mnist_add/get_mnist_add.py +++ b/datasets/mnist_add/get_mnist_add.py @@ -3,25 +3,22 @@ import torchvision from torch.utils.data import Dataset from torchvision.transforms import transforms +def get_data(file, img_dataset): + X = [] + Y = [] + with open(file) as f: + for line in f: + line = line.strip().split(' ') + X.append((img_dataset[int(line[0])][0], img_dataset[int(line[1])][0])) + Y.append(int(line[2])) + return X, Y + def get_mnist_add(): transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081, ))]) img_dataset = torchvision.datasets.MNIST(root='./', train=True, download=True, transform=transform) - train_X = [] - train_Y = [] - with open('./train_data.txt') as f: - for line in f: - line = line.strip().split(' ') - train_X.append((img_dataset[int(line[0])][0], img_dataset[int(line[1])][0])) - train_Y.append(int(line[2])) - - test_X = [] - test_Y = [] - with open('./test_data.txt') as f: - for line in f: - line = line.strip().split(' ') - test_X.append((img_dataset[int(line[0])][0], img_dataset[int(line[1])][0])) - test_Y.append(int(line[2])) + train_X, train_Y = get_data('./train_data.txt', img_dataset) + test_X, test_Y = get_data('./test_data.txt', img_dataset) return train_X, train_Y, test_X, test_Y @@ -29,4 +26,3 @@ if __name__ == "__main__": train_X, train_Y, test_X, test_Y = get_mnist_add() print(len(train_X), len(test_X)) print(train_X[0][0].shape, train_X[0][1].shape, train_Y[0]) - From f9812e319958b99ff2185fe88f4797119bac7ccf Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 16 Nov 2022 13:22:54 +0800 Subject: [PATCH 019/601] Update get_mnist_add.py --- datasets/mnist_add/get_mnist_add.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/datasets/mnist_add/get_mnist_add.py b/datasets/mnist_add/get_mnist_add.py index 183f9a5..eb75e47 100644 --- a/datasets/mnist_add/get_mnist_add.py +++ b/datasets/mnist_add/get_mnist_add.py @@ -9,7 +9,7 @@ def get_data(file, img_dataset): with open(file) as f: for line in f: line = line.strip().split(' ') - X.append((img_dataset[int(line[0])][0], img_dataset[int(line[1])][0])) + X.append([img_dataset[int(line[0])][0], img_dataset[int(line[1])][0]]) Y.append(int(line[2])) return X, Y @@ -26,3 +26,4 @@ if __name__ == "__main__": train_X, train_Y, test_X, test_Y = get_mnist_add() print(len(train_X), len(test_X)) print(train_X[0][0].shape, train_X[0][1].shape, train_Y[0]) + From 05ae1517b9eb8c3c5c13f3ca570052f05c7879c6 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 16 Nov 2022 13:40:08 +0800 Subject: [PATCH 020/601] Create get_hwf.py --- datasets/hwf/get_hwf.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 datasets/hwf/get_hwf.py diff --git a/datasets/hwf/get_hwf.py b/datasets/hwf/get_hwf.py new file mode 100644 index 0000000..98eea5e --- /dev/null +++ b/datasets/hwf/get_hwf.py @@ -0,0 +1,36 @@ +import json +from PIL import Image +from torchvision.transforms import transforms + +img_transform = transforms.Compose([ + transforms.ToTensor(), + transforms.Normalize((0.5,), (1,)) + ]) + +def get_data(file): + X = [] + Y = [] + img_dir = './data/Handwritten_Math_Symbols/' + with open(file) as f: + data = json.load(f) + for idx in range(len(data)): + imgs = [] + for img_path in data[idx]['img_paths']: + img = Image.open(img_dir + img_path).convert('L') + img = img_transform(img) + imgs.append(img) + X.append(imgs) + Y.append(data[idx]['res']) + return X, Y + +def get_hwf(): + train_X, train_Y = get_data('./data/expr_train.json') + test_X, test_Y = get_data('./data/expr_test.json') + + return train_X, train_Y, test_X, test_Y + +if __name__ == "__main__": + train_X, train_Y, test_X, test_Y = get_hwf() + print(len(train_X), len(test_X)) + print(len(train_X[0]), train_X[0][0].shape, train_Y[0]) + From eaeaba3e721fe93920133418155703b41d203c82 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 16 Nov 2022 13:42:36 +0800 Subject: [PATCH 021/601] Create README.md --- datasets/hwf/README.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 datasets/hwf/README.md diff --git a/datasets/hwf/README.md b/datasets/hwf/README.md new file mode 100644 index 0000000..b8f3047 --- /dev/null +++ b/datasets/hwf/README.md @@ -0,0 +1,4 @@ +Download the Handwritten Formula Recognition dataset from [google drive](https://drive.google.com/file/d/1G07kw-wK-rqbg_85tuB7FNfA49q8lvoy/view?usp=sharing) to this folder and unzip it: +``` +unzip HWF.zip +``` From 3616608aaf61f6cb03e2f2cb55145f27844c0fee Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 17 Nov 2022 10:24:50 +0800 Subject: [PATCH 022/601] Update get_mnist_add.py --- datasets/mnist_add/get_mnist_add.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/datasets/mnist_add/get_mnist_add.py b/datasets/mnist_add/get_mnist_add.py index eb75e47..fcada50 100644 --- a/datasets/mnist_add/get_mnist_add.py +++ b/datasets/mnist_add/get_mnist_add.py @@ -15,10 +15,10 @@ def get_data(file, img_dataset): def get_mnist_add(): transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081, ))]) - img_dataset = torchvision.datasets.MNIST(root='./', train=True, download=True, transform=transform) + img_dataset = torchvision.datasets.MNIST(root='./datasets/mnist_add/', train=True, download=True, transform=transform) - train_X, train_Y = get_data('./train_data.txt', img_dataset) - test_X, test_Y = get_data('./test_data.txt', img_dataset) + train_X, train_Y = get_data('./datasets/mnist_add/train_data.txt', img_dataset) + test_X, test_Y = get_data('./datasets/mnist_add/test_data.txt', img_dataset) return train_X, train_Y, test_X, test_Y From 22de038d343487e81600fd2ba1a36c722590e6f6 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 17 Nov 2022 10:26:15 +0800 Subject: [PATCH 023/601] Update get_hwf.py --- datasets/hwf/get_hwf.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/datasets/hwf/get_hwf.py b/datasets/hwf/get_hwf.py index 98eea5e..cfd1666 100644 --- a/datasets/hwf/get_hwf.py +++ b/datasets/hwf/get_hwf.py @@ -7,10 +7,10 @@ img_transform = transforms.Compose([ transforms.Normalize((0.5,), (1,)) ]) -def get_data(file): +def get_data(file, precision_num = 2): X = [] Y = [] - img_dir = './data/Handwritten_Math_Symbols/' + img_dir = './datasets/hwf/data/Handwritten_Math_Symbols/' with open(file) as f: data = json.load(f) for idx in range(len(data)): @@ -20,12 +20,12 @@ def get_data(file): img = img_transform(img) imgs.append(img) X.append(imgs) - Y.append(data[idx]['res']) + Y.append(round(data[idx]['res'], precision_num)) return X, Y -def get_hwf(): - train_X, train_Y = get_data('./data/expr_train.json') - test_X, test_Y = get_data('./data/expr_test.json') +def get_hwf(precision_num = 2): + train_X, train_Y = get_data('./datasets/hwf/data/expr_train.json', precision_num) + test_X, test_Y = get_data('./datasets/hwf/data/expr_test.json', precision_num) return train_X, train_Y, test_X, test_Y From f6f92a5f083adfc420a806fab565ae8d07cf788b Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 17 Nov 2022 10:29:45 +0800 Subject: [PATCH 024/601] Update kb.py --- abducer/kb.py | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 5d25a46..12772e5 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -45,9 +45,9 @@ class KBBase(ABC): pass class add_KB(KBBase): - def __init__(self, pseudo_label_list, kb_max_len = -1): + def __init__(self, kb_max_len = -1): super().__init__() - self.pseudo_label_list = pseudo_label_list + self.pseudo_label_list = list(range(10)) self.base = {} self.kb_max_len = kb_max_len if(self.kb_max_len > 0): @@ -92,9 +92,9 @@ class add_KB(KBBase): return sum(self._dict_len(v) for v in self.base.values()) class hwf_KB(KBBase): - def __init__(self, pseudo_label_list, kb_max_len = -1): + def __init__(self, kb_max_len = -1): super().__init__() - self.pseudo_label_list = pseudo_label_list + self.pseudo_label_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', '*', '/'] self.base = {} self.kb_max_len = kb_max_len if(self.kb_max_len > 0): @@ -157,13 +157,13 @@ class hwf_KB(KBBase): def valid_formula(self, formula): symbol_idx_list = [] - first_minus_flag = 0 for idx, c in enumerate(formula): if(idx == 0 and c == '-'): - first_minus_flag = 1 + if(len(formula) == 1 or formula[1] in ['+', '-', '*', '/']): + return False continue if(c in ['+', '-', '*', '/']): - if(idx - 1 in symbol_idx_list or (idx == 1 and first_minus_flag == 1)): + if(idx - 1 in symbol_idx_list): return False symbol_idx_list.append(idx) if(0 in symbol_idx_list or len(formula) - 1 in symbol_idx_list): @@ -289,8 +289,7 @@ class reg_KB(KBBase): if __name__ == "__main__": # With ground KB - pseudo_label_list = list(range(10)) - kb = add_KB(pseudo_label_list, kb_max_len = 5) + kb = add_KB(kb_max_len = 5) print('len(kb):', len(kb)) res = kb.get_candidates(0) print(res) @@ -303,8 +302,7 @@ if __name__ == "__main__": print() # Without ground KB - pseudo_label_list = list(range(10)) - kb = add_KB(pseudo_label_list) + kb = add_KB() print('len(kb):', len(kb)) res = kb.get_candidates(0) print(res) @@ -316,8 +314,7 @@ if __name__ == "__main__": print(res) print() - pseudo_label_list = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '+', '-', '*', '/'] - kb = hwf_KB(pseudo_label_list, kb_max_len = 5) + kb = hwf_KB(kb_max_len = 5) print('len(kb):', len(kb)) res = kb.get_candidates(1, length = 3) print(res) From 70fa5cf56a941fe9508a89e1a3f43cb76bc92727 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 17 Nov 2022 10:31:18 +0800 Subject: [PATCH 025/601] Update abducer_base.py --- abducer/abducer_base.py | 52 +++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 576cce4..1168ea6 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -11,7 +11,8 @@ #================================================================# import abc -from kb import add_KB, hwf_KB +# from kb import add_KB, hwf_KB +from abducer.kb import add_KB, hwf_KB import numpy as np from itertools import product, combinations @@ -37,18 +38,19 @@ def confidence_dist(A, B): class AbducerBase(abc.ABC): - def __init__(self, kb, dist_func = "hamming", pred_res_parse = None, cache = True): + def __init__(self, kb, dist_func = 'hamming', pred_res_parse = None, cache = True): self.kb = kb - if dist_func == "hamming": - dist_func = hamming_dist - elif dist_func == "confidence": - dist_func = confidence_dist - self.dist_func = dist_func + + if(dist_func == 'hamming'): + self.dist_func = hamming_dist + elif(dist_func == 'confidence'): + self.dist_func = confidence_dist + if pred_res_parse is None: - if(dist_func == "hamming"): + if(dist_func == 'hamming'): pred_res_parse = lambda x : x["cls"] - elif dist_func == "confidence": - pred_res_parse = lambda x : x[" "] + elif dist_func == 'confidence': + pred_res_parse = lambda x : x["prob"] self.pred_res_parse = pred_res_parse self.cache = cache @@ -61,20 +63,24 @@ class AbducerBase(abc.ABC): idxs = np.where(cost_list == min_address_num)[0] return [candidates[idx] for idx in idxs][0] - def abduce(self, data, max_address_num = 3, require_more_address = 0, length = -1): + def abduce(self, data, max_address_num = -1, require_more_address = 0): pred_res, ans = data + pred_res = [self.kb.pseudo_label_list[sym] for sym in pred_res] + - if length == -1: - length = len(pred_res) + if max_address_num == -1: + max_address_num = len(pred_res) if(self.cache and (tuple(pred_res), ans) in self.cache_min_address_num): address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), ans)] + require_more_address) if((tuple(pred_res), ans, address_num) in self.cache_candidates): - print('cached') - return self.cache_candidates[(tuple(pred_res), ans, address_num)] + # print('cached') + candidates = self.cache_candidates[(tuple(pred_res), ans, address_num)] + candidates = self.get_min_cost_candidate(pred_res, candidates) + return candidates if(self.kb.base != {}): - all_candidates = self.kb.get_candidates(ans, length) + all_candidates = self.kb.get_candidates(ans, len(pred_res)) cost_list = self.dist_func(pred_res, all_candidates) min_address_num = np.min(cost_list) address_num = min(max_address_num, min_address_num + require_more_address) @@ -107,7 +113,6 @@ class AbducerBase(abc.ABC): def get_abduce_candidates(self, pred_res, key, max_address_num, require_more_address): candidates = [] - for address_num in range(len(pred_res) + 1): if(address_num > max_address_num): print('No candidates found') @@ -132,22 +137,20 @@ class AbducerBase(abc.ABC): return candidates, min_address_num, address_num - - - def batch_abduce(self, Y, C, max_address_num = 3, require_more_address = 0): + + def batch_abduce(self, Y, C, max_address_num = -1, require_more_address = 0): return [ self.abduce((y, c), max_address_num, require_more_address)\ for y, c in zip(self.pred_res_parse(Y), C) ] - def __call__(self, Y, C, max_address_num = 3, require_more_address = 0): + def __call__(self, Y, C, max_address_num = -1, require_more_address = 0): return self.batch_abduce(Y, C, max_address_num, require_more_address) if __name__ == "__main__": - pseudo_label_list = list(range(10)) - kb = add_KB(pseudo_label_list) + kb = add_KB() abd = AbducerBase(kb) res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 0) print(res) @@ -161,8 +164,7 @@ if __name__ == "__main__": print(res) print() - pseudo_label_list = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '+', '-', '*', '/'] - kb = hwf_KB(pseudo_label_list) + kb = hwf_KB() abd = AbducerBase(kb) res = abd.abduce((['5', '+', '2'], 3), max_address_num = 2, require_more_address = 0) print(res) From c0fd799c5ddba479a214a597b6a9f9b11b00be2d Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 17 Nov 2022 10:31:48 +0800 Subject: [PATCH 026/601] Update basic_model.py --- models/basic_model.py | 134 ++++++------------------------------------ 1 file changed, 17 insertions(+), 117 deletions(-) diff --git a/models/basic_model.py b/models/basic_model.py index 47aeab9..3885067 100644 --- a/models/basic_model.py +++ b/models/basic_model.py @@ -14,47 +14,11 @@ import sys sys.path.append("..") import torch -from torch.autograd import Variable from torch.utils.data import Dataset -import torchvision import os from multiprocessing import Pool -import random -import torch -from torch.utils.data import Dataset -from torch.utils.data import sampler -import torchvision.transforms as transforms -import six -import sys -from PIL import Image -import numpy as np -import collections - -class resizeNormalize(object): - - def __init__(self, size, interpolation=Image.BILINEAR): - self.size = size - self.interpolation = interpolation - self.toTensor = transforms.ToTensor() - self.transform = transforms.Compose([ - #transforms.ToPILImage(), - #transforms.RandomHorizontalFlip(), - #transforms.RandomVerticalFlip(), - #transforms.RandomRotation(30), - #transforms.RandomAffine(30), - transforms.ToTensor(), - - ]) - - def __call__(self, img): - #img = img.resize(self.size, self.interpolation) - #img = self.toTensor(img) - img = self.transform(img) - img.sub_(0.5).div_(0.5) - return img - class XYDataset(Dataset): def __init__(self, X, Y, transform=None, target_transform=None): self.X = X @@ -80,36 +44,6 @@ class XYDataset(Dataset): return (img, label, index) -class alignCollate(object): - - def __init__(self, imgH=32, imgW=100, keep_ratio=False, min_ratio=1): - self.imgH = imgH - self.imgW = imgW - self.keep_ratio = keep_ratio - self.min_ratio = min_ratio - - def __call__(self, batch): - images, labels, img_keys = zip(*batch) - - imgH = self.imgH - imgW = self.imgW - if self.keep_ratio: - ratios = [] - for image in images: - w, h = image.shape[:2] - ratios.append(w / float(h)) - ratios.sort() - max_ratio = ratios[-1] - imgW = int(np.floor(max_ratio * imgH)) - imgW = max(imgH * self.min_ratio, imgW) # assure imgH >= imgW - - transform = resizeNormalize((imgW, imgH)) - images = [transform(image) for image in images] - images = torch.cat([t.unsqueeze(0) for t in images], 0) - labels = torch.LongTensor(labels) - - return images, labels, img_keys - class FakeRecorder(): def __init__(self): pass @@ -117,20 +51,6 @@ class FakeRecorder(): def print(self, *x): pass -from torch.nn import init -from torch import nn - -def weigth_init(m): - if isinstance(m, nn.Conv2d): - init.xavier_uniform_(m.weight.data) - init.constant_(m.bias.data,0.1) - elif isinstance(m, nn.BatchNorm2d): - m.weight.data.fill_(1) - m.bias.data.zero_() - elif isinstance(m, nn.Linear): - m.weight.data.normal_(0,0.01) - m.bias.data.zero_() - class BasicModel(): def __init__(self, model, @@ -142,7 +62,6 @@ class BasicModel(): transform = None, target_transform=None, collate_fn = None, - pretrained = False, recorder = None): self.model = model.to(device) @@ -153,7 +72,7 @@ class BasicModel(): self.target_transform = target_transform self.device = device - sign_list = sorted(list(set(sign_list))) + self.sign_list = sorted(list(set(sign_list))) self.mapping = dict(zip(sign_list, list(range(len(sign_list))))) self.remapping = dict(zip(list(range(len(sign_list))), sign_list)) @@ -161,12 +80,6 @@ class BasicModel(): recorder = FakeRecorder() self.recorder = recorder - if pretrained: - # the paths of model, optimizer should be included in params - self.load(params.load_dir) - else: - self.model.apply(weigth_init) - self.save_interval = params.saveInterval self.params = params self.collate_fn = collate_fn @@ -211,41 +124,28 @@ class BasicModel(): return self._fit(data_loader, params.n_epoch, params.stop_loss) def train_epoch(self, data_loader): - # loss_avg = mutils.averager() - self.model.train() - - loss_value = 0 - for i, data in enumerate(data_loader): - X = data[0] - Y = data[1] - loss = self.train_batch(X, Y) - loss_value += loss.item() - - return loss_value - - def train_batch(self, X, Y): - #cpu_images, cpu_texts, _ = data model = self.model criterion = self.criterion optimizer = self.optimizer device = self.device - - # init training status - # torch.autograd.set_detect_anomaly(True) + + model.train() + + loss_value = 0 + for _, data in enumerate(data_loader): + X = data[0].to(device) + Y = data[1].to(device) + pred_Y = model(X) - # model predict - X = X.to(device) - Y = Y.to(device) - pred_Y = model(X) + loss = criterion(pred_Y, Y) - # calculate loss - loss = criterion(pred_Y, Y) + optimizer.zero_grad() + loss.backward() + optimizer.step() - # back propagation and optimize - optimizer.zero_grad() - loss.backward() - optimizer.step() - return loss + loss_value += loss.item() + + return loss_value def _predict(self, data_loader): model = self.model @@ -297,7 +197,7 @@ class BasicModel(): recorder = self.recorder recorder.print('Start Predict ', print_prefix) - return torch.softmax(self._predict(data_loader), axis=1) + return torch.softmax(self._predict(data_loader), axis=1).cpu() def _val(self, data_loader, print_prefix): model = self.model From baa8a366d20e32bc7ddaef89cb0b827e9e04adb7 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 17 Nov 2022 10:34:13 +0800 Subject: [PATCH 027/601] Create example.py --- example.py | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 example.py diff --git a/example.py b/example.py new file mode 100644 index 0000000..405e2bd --- /dev/null +++ b/example.py @@ -0,0 +1,85 @@ +# coding: utf-8 +#================================================================# +# Copyright (C) 2021 Freecss All rights reserved. +# +# File Name :share_example.py +# Author :freecss +# Email :karlfreecss@gmail.com +# Created Date :2021/06/07 +# Description : +# +#================================================================# + +from utils.plog import logger +from models.wabl_models import DecisionTree, KNN +import pickle as pk +import numpy as np +import time +import framework +import utils.plog as plog +import torch.nn as nn +import torch + +from models.lenet5 import LeNet5 +from models.basic_model import BasicModel +from models.wabl_models import MyModel + +from multiprocessing import Pool +import os +from datasets.data_generator import generate_data_via_codes, code_generator +from collections import defaultdict +from abducer.abducer_base import AbducerBase +from abducer.kb import add_KB, hwf_KB +from datasets.mnist_add.get_mnist_add import get_mnist_add +from datasets.hwf.get_hwf import get_hwf + +class Params: + imgH = 45 + imgW = 45 + keep_ratio = True + saveInterval = 10 + batchSize = 16 + workers = 16 + n_epoch = 10 + stop_loss = None + +def run_test(): + + result_dir = 'results' + + recorder_file_path = f"{result_dir}/1116.pk"# + + # words = code_generator(code_len, code_num, letter_num) + kb = add_KB() + abducer = AbducerBase(kb) + + recorder = logger() + recorder.set_savefile("test.log") + + + train_X, train_Y, test_X, test_Y = get_mnist_add() + # train_X, train_Y, test_X, test_Y = get_hwf() + + + recorder = plog.ResultRecorder() + cls = LeNet5() + + criterion = nn.CrossEntropyLoss(size_average=True) + optimizer = torch.optim.Adam(cls.parameters(), lr=0.001, betas=(0.9, 0.99)) + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + sign_list = list(range(10)) + base_model = BasicModel(cls, criterion, optimizer, device, Params(), sign_list, recorder=recorder) + model = MyModel(base_model) + + res = framework.train(model, abducer, train_X, train_Y, logic_forward = kb.logic_forward, sample_num = 10000, verbose = 1) + print(res) + + + recorder.dump(open(recorder_file_path, "wb")) + return True + +if __name__ == "__main__": + os.system("mkdir results") + + run_test() + From dc1b669ab225d40711b2c1988fa37297399f36eb Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 17 Nov 2022 10:37:01 +0800 Subject: [PATCH 028/601] Update framework.py --- framework.py | 161 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 102 insertions(+), 59 deletions(-) diff --git a/framework.py b/framework.py index b41a334..27c2dba 100644 --- a/framework.py +++ b/framework.py @@ -17,17 +17,17 @@ import numpy as np from utils.plog import INFO, DEBUG, clocker @clocker -def block_sample(X_bak, Y_bak, C_bak, sample_num, epoch_idx): +def block_sample(X_bak, C_bak, sample_num, epoch_idx): part_num = (len(X_bak) // sample_num) if part_num == 0: part_num = 1 seg_idx = epoch_idx % part_num INFO("seg_idx:", seg_idx, ", part num:", part_num, ", data num:", len(X_bak)) X = X_bak[sample_num * seg_idx: sample_num * (seg_idx + 1)] - Y = Y_bak[sample_num * seg_idx: sample_num * (seg_idx + 1)] + # Y = Y_bak[sample_num * seg_idx: sample_num * (seg_idx + 1)] C = C_bak[sample_num * seg_idx: sample_num * (seg_idx + 1)] - return X, Y, C + return X, C def get_taglist(self, Y): tmp = [[str(x) for x in label] for label in Y] @@ -35,49 +35,58 @@ def get_taglist(self, Y): return tmp @clocker -def result_statistics(pseudo_Y, Y, abduced_Y): - - abd_err_num = 0 - abd_char_num = 0 - abd_char_acc = 0 - abd_failed = 0 - word_err_num = 0 +def result_statistics(C, pseudo_Y, logic_forward): + abl_acc = 0 + for tidx, (c, pseudo_y) in enumerate(zip(C, pseudo_Y)): + if(logic_forward(pseudo_y) == c): + abl_acc += 1 + - ori_char_num = 0 - ori_char_acc = 0 + return abl_acc / len(C) - for tidx, (pseudo_y, y, abduced_y) in enumerate(zip(pseudo_Y, Y, abduced_Y)): - pseudo_y = pseudo_y - if sum(abduced_y != y) != 0: - abd_err_num += 1 - if abduced_y is not None: - abd_char_num += len(y) - abd_char_acc += sum(abduced_y == y) - else: - abd_failed += 1 +# def result_statistics(pseudo_Y, Y, abduced_Y): - ori_char_num += len(pseudo_y) - ori_char_acc += sum(pseudo_y == y) +# abd_err_num = 0 +# abd_char_num = 0 +# abd_char_acc = 0 +# abd_failed = 0 +# word_err_num = 0 + +# ori_char_num = 0 +# ori_char_acc = 0 + +# for tidx, (pseudo_y, y, abduced_y) in enumerate(zip(pseudo_Y, Y, abduced_Y)): +# pseudo_y = pseudo_y +# if sum(abduced_y != y) != 0: +# abd_err_num += 1 +# if abduced_y is not None: +# abd_char_num += len(y) +# abd_char_acc += sum(abduced_y == y) +# else: +# abd_failed += 1 + +# ori_char_num += len(pseudo_y) +# ori_char_acc += sum(pseudo_y == y) - if abduced_y is not None and sum(y != pseudo_y) == 0 and sum(pseudo_y != abduced_y) > 0: - INFO(pseudo_y, y, abduced_y) - pk.dump((pseudo_y, y, abduced_y), open("bug.pk", "wb")) +# if abduced_y is not None and sum(y != pseudo_y) == 0 and sum(pseudo_y != abduced_y) > 0: +# INFO(pseudo_y, y, abduced_y) +# pk.dump((pseudo_y, y, abduced_y), open("bug.pk", "wb")) - if sum(pseudo_y != y) != 0: - word_err_num += 1 +# if sum(pseudo_y != y) != 0: +# word_err_num += 1 - INFO("") - INFO("Abd word level accuracy:", 1 - word_err_num / len(pseudo_Y)) - INFO("Abd char level accuracy:", abd_char_acc / abd_char_num) - INFO("Ori char level accuracy:", ori_char_acc / ori_char_num) - INFO("") +# INFO("") +# INFO("Abd word level accuracy:", 1 - word_err_num / len(pseudo_Y)) +# INFO("Abd char level accuracy:", abd_char_acc / abd_char_num) +# INFO("Ori char level accuracy:", ori_char_acc / ori_char_num) +# INFO("") - result = {"total_word" : len(pseudo_Y), "accuracy_word" : len(pseudo_Y) - word_err_num, - "total_abd_char": abd_char_num, "accuracy_abd_char" : abd_char_acc, - "total_ori_char": ori_char_num, "accuracy_ori_char" : ori_char_acc, - "total_abd_failed": abd_failed} +# result = {"total_word" : len(pseudo_Y), "accuracy_word" : len(pseudo_Y) - word_err_num, +# "total_abd_char": abd_char_num, "accuracy_abd_char" : abd_char_acc, +# "total_ori_char": ori_char_num, "accuracy_ori_char" : ori_char_acc, +# "total_abd_failed": abd_failed} - return result +# return result @clocker def filter_data(X, abduced_Y): @@ -106,7 +115,7 @@ def is_all_sublabel_exist(labels, std_label_list): def pretrain(model, X, Y): pass -def train(model, abducer, X, Y, C = None, epochs = 10, sample_num = -1, verbose = -1, check_sublabel = True): +def train(model, abducer, X, C, logic_forward, epochs = 10, sample_num = -1, verbose = -1): # Set default parameters if sample_num == -1: sample_num = len(X) @@ -114,42 +123,76 @@ def train(model, abducer, X, Y, C = None, epochs = 10, sample_num = -1, verbose if verbose < 1: verbose = epochs - if C is None: - C = [None] * len(X) - - # Set function running time recorder - valid_func = clocker(model.valid) predict_func = clocker(model.predict) train_func = clocker(model.train) abduce_func = clocker(abducer.batch_abduce) X_bak = X - Y_bak = Y C_bak = C - + epochs = 50 # Abductive learning train process - res = {} for epoch_idx in range(epochs): - X, Y, C = block_sample(X_bak, Y_bak, C_bak, sample_num, epoch_idx) + X, C = block_sample(X_bak, C_bak, sample_num, epoch_idx) preds_res = predict_func(X) + + abl_acc = result_statistics(C, preds_res['cls'], logic_forward) + print('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc) + abduced_Y = abduce_func(preds_res, C) - finetune_X, finetune_Y = filter_data(X, abduced_Y) - score, score_list = valid_func(X, Y) - if ((epoch_idx + 1) % verbose == 0) or (epoch_idx == epochs - 1): - res = result_statistics(preds_res["cls"], Y, abduced_Y) - INFO(res) - - if check_sublabel and (not is_all_sublabel_exist(finetune_Y, model.label_lists)): - INFO("There is some sub label missing", len(finetune_Y)) - break + + finetune_X, finetune_Y = filter_data(X, abduced_Y) + if len(finetune_X) > 0: train_func(finetune_X, finetune_Y)#, n_epoch = 10) else: INFO("lack of data, all abduced failed", len(finetune_X)) - return res - #return ret + return abl_acc + +# def train(model, abducer, X, Y, C = None, epochs = 10, sample_num = -1, verbose = -1, check_sublabel = True): +# # Set default parameters +# if sample_num == -1: +# sample_num = len(X) + +# if verbose < 1: +# verbose = epochs + +# if C is None: +# C = [None] * len(X) + +# # Set function running time recorder +# valid_func = clocker(model.valid) +# predict_func = clocker(model.predict) +# train_func = clocker(model.train) + +# abduce_func = clocker(abducer.batch_abduce) + +# X_bak = X +# Y_bak = Y +# C_bak = C + +# # Abductive learning train process +# res = {} +# for epoch_idx in range(epochs): +# X, Y, C = block_sample(X_bak, Y_bak, C_bak, sample_num, epoch_idx) +# preds_res = predict_func(X) +# abduced_Y = abduce_func(preds_res, C) +# finetune_X, finetune_Y = filter_data(X, abduced_Y) +# score, score_list = valid_func(X, Y) +# if ((epoch_idx + 1) % verbose == 0) or (epoch_idx == epochs - 1): +# res = result_statistics(preds_res["cls"], Y, abduced_Y) +# INFO(res) + +# if check_sublabel and (not is_all_sublabel_exist(finetune_Y, model.label_lists)): +# INFO("There is some sub label missing", len(finetune_Y)) +# break + +# if len(finetune_X) > 0: +# train_func(finetune_X, finetune_Y)#, n_epoch = 10) +# else: +# INFO("lack of data, all abduced failed", len(finetune_X)) +# return res if __name__ == "__main__": pass From 9f8589d0cbe157f372fd8dad676c01be61c78b77 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 17 Nov 2022 10:50:11 +0800 Subject: [PATCH 029/601] Update example.py --- example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example.py b/example.py index 405e2bd..7eb8b03 100644 --- a/example.py +++ b/example.py @@ -71,7 +71,7 @@ def run_test(): base_model = BasicModel(cls, criterion, optimizer, device, Params(), sign_list, recorder=recorder) model = MyModel(base_model) - res = framework.train(model, abducer, train_X, train_Y, logic_forward = kb.logic_forward, sample_num = 10000, verbose = 1) + res = framework.train(model, abducer, train_X, train_Y, sample_num = 10000, verbose = 1) print(res) From d42db9a52e81c642f933af1252959b24d200bc64 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 17 Nov 2022 10:50:34 +0800 Subject: [PATCH 030/601] Update framework.py --- framework.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework.py b/framework.py index 27c2dba..92a20b5 100644 --- a/framework.py +++ b/framework.py @@ -115,7 +115,7 @@ def is_all_sublabel_exist(labels, std_label_list): def pretrain(model, X, Y): pass -def train(model, abducer, X, C, logic_forward, epochs = 10, sample_num = -1, verbose = -1): +def train(model, abducer, X, C, epochs = 10, sample_num = -1, verbose = -1): # Set default parameters if sample_num == -1: sample_num = len(X) @@ -136,7 +136,7 @@ def train(model, abducer, X, C, logic_forward, epochs = 10, sample_num = -1, ver X, C = block_sample(X_bak, C_bak, sample_num, epoch_idx) preds_res = predict_func(X) - abl_acc = result_statistics(C, preds_res['cls'], logic_forward) + abl_acc = result_statistics(C, preds_res['cls'], abducer.kb.logic_forward) print('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc) abduced_Y = abduce_func(preds_res, C) From 9980102b015e4852ad54b4e032024a77510a57b8 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 17 Nov 2022 16:28:03 +0800 Subject: [PATCH 031/601] Update abducer_base.py --- abducer/abducer_base.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 1168ea6..23019b8 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -65,8 +65,6 @@ class AbducerBase(abc.ABC): def abduce(self, data, max_address_num = -1, require_more_address = 0): pred_res, ans = data - pred_res = [self.kb.pseudo_label_list[sym] for sym in pred_res] - if max_address_num == -1: max_address_num = len(pred_res) From 7505852a58f9b381a9308c33aefd83ca1bf4c498 Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Thu, 17 Nov 2022 21:34:11 +0800 Subject: [PATCH 032/601] update basic_model.py --- models/basic_model.py | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/models/basic_model.py b/models/basic_model.py index 3885067..e251ec4 100644 --- a/models/basic_model.py +++ b/models/basic_model.py @@ -58,7 +58,6 @@ class BasicModel(): optimizer, device, params, - sign_list, transform = None, target_transform=None, collate_fn = None, @@ -72,10 +71,6 @@ class BasicModel(): self.target_transform = target_transform self.device = device - self.sign_list = sorted(list(set(sign_list))) - self.mapping = dict(zip(sign_list, list(range(len(sign_list))))) - self.remapping = dict(zip(list(range(len(sign_list))), sign_list)) - if recorder is None: recorder = FakeRecorder() self.recorder = recorder @@ -89,7 +84,7 @@ class BasicModel(): recorder = self.recorder recorder.print("model fitting") - min_loss = 999999999 + min_loss = 999999999 for epoch in range(n_epoch): loss_value = self.train_epoch(data_loader) recorder.print(f"{epoch}/{n_epoch} model training loss is {loss_value}") @@ -103,9 +98,6 @@ class BasicModel(): recorder.print("Model fitted, minimal loss is ", min_loss) return loss_value - def str2ints(self, Y): - return [self.mapping[y] for y in Y] - def fit(self, data_loader = None, X = None, y = None): @@ -115,8 +107,7 @@ class BasicModel(): transform = self.transform target_transform = self.target_transform - Y = self.str2ints(y) - train_dataset = XYDataset(X, Y, transform=transform, target_transform=target_transform) + train_dataset = XYDataset(X, y, transform=transform, target_transform=target_transform) sampler = None data_loader = torch.utils.data.DataLoader(train_dataset, batch_size=params.batchSize, \ shuffle=True, sampler=sampler, num_workers=int(params.workers), \ @@ -155,7 +146,7 @@ class BasicModel(): with torch.no_grad(): results = [] - for i, data in enumerate(data_loader): + for _, data in enumerate(data_loader): X = data[0].to(device) pred_Y = model(X) results.append(pred_Y) @@ -179,7 +170,7 @@ class BasicModel(): recorder = self.recorder recorder.print('Start Predict ', print_prefix) Y = self._predict(data_loader).argmax(axis=1) - return [self.remapping[int(y)] for y in Y] + return [int(y) for y in Y] def predict_proba(self, data_loader = None, X = None, print_prefix = ""): if data_loader is None: @@ -197,7 +188,7 @@ class BasicModel(): recorder = self.recorder recorder.print('Start Predict ', print_prefix) - return torch.softmax(self._predict(data_loader), axis=1).cpu() + return torch.softmax(self._predict(data_loader), axis=1).cpu().numpy() def _val(self, data_loader, print_prefix): model = self.model @@ -212,7 +203,7 @@ class BasicModel(): pred_num = 0 loss_value = 0 with torch.no_grad(): - for i, data in enumerate(data_loader): + for _, data in enumerate(data_loader): X = data[0].to(device) Y = data[1].to(device) @@ -236,8 +227,7 @@ class BasicModel(): transform = self.transform target_transform = self.target_transform - Y = self.str2ints(y) - val_dataset = XYDataset(X, Y, transform=transform, target_transform=target_transform) + val_dataset = XYDataset(X, y, transform=transform, target_transform=target_transform) sampler = None data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=params.batchSize, \ shuffle=True, sampler=sampler, num_workers=int(params.workers), \ From a61ee9cd54d55f2ee3b74e27f7cd21655234f8c9 Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Thu, 17 Nov 2022 21:42:14 +0800 Subject: [PATCH 033/601] update lenet5.py --- models/lenet5.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/models/lenet5.py b/models/lenet5.py index 9d5b054..56c1ca6 100644 --- a/models/lenet5.py +++ b/models/lenet5.py @@ -20,21 +20,24 @@ from torch import nn from torch.nn import functional as F from torch.autograd import Variable import torchvision.transforms as transforms +import numpy as np from models.basic_model import BasicModel - import utils.plog as plog class LeNet5(nn.Module): - def __init__(self): + def __init__(self, num_classes=10, image_size=(28, 28)): super().__init__() self.conv1 = nn.Conv2d(1, 6, 3, padding=1) self.conv2 = nn.Conv2d(6, 16, 3) self.conv3 = nn.Conv2d(16, 16, 3) - self.fc1 = nn.Linear(256, 120) + feature_map_size = ((np.array(image_size) // 2 - 2) // 2 - 2) + num_features = 16 * feature_map_size[0] * feature_map_size[1] + + self.fc1 = nn.Linear(num_features, 120) self.fc2 = nn.Linear(120, 84) - self.fc3 = nn.Linear(84, 10) + self.fc3 = nn.Linear(84, num_classes) def forward(self, x): '''å‰å‘传播函数''' From b521dd1cb049666381bf9390737c4b3fbb57236d Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Thu, 17 Nov 2022 21:43:53 +0800 Subject: [PATCH 034/601] update wabl_models.py --- models/wabl_models.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/models/wabl_models.py b/models/wabl_models.py index 15fe6e6..5d44719 100644 --- a/models/wabl_models.py +++ b/models/wabl_models.py @@ -48,19 +48,17 @@ def reshape_data(Y, marks): class WABLBasicModel: - """ - label_lists 的目标在于为å„个符å·è®¾ç½®ç¼–å·ï¼Œæ— è®ºæ–¹æ³•是给出字典形å¼çš„æ¦‚率还是给出listå½¢å¼çš„,都å¯ä»¥é€šè¿‡è¿™ç§æ–¹å¼è§£å†³. - åŽç»­å¯èƒ½ä¼šè€ƒè™‘更加完善的措施,é™ä½Žè¿™éƒ¨åˆ†çš„夿‚度 - 当模型共享的时候,label_lists 之间的元素也是共享的 - """ - def __init__(self): - pass + def __init__(self, pseudo_label_list): + self.pseudo_label_list = pseudo_label_list + self.mapping = dict(zip(pseudo_label_list, list(range(len(pseudo_label_list))))) + self.remapping = dict(zip(list(range(len(pseudo_label_list))), pseudo_label_list)) def predict(self, X): data_X, marks = merge_data(X) prob = self.cls_list[0].predict_proba(X = data_X) - cls = np.array(prob).argmax(axis = 1) + _cls = prob.argmax(axis = 1) + cls = list(map(lambda x : self.remapping[x], _cls)) prob = reshape_data(prob, marks) cls = reshape_data(cls, marks) @@ -69,14 +67,16 @@ class WABLBasicModel: def valid(self, X, Y): data_X, _ = merge_data(X) - data_Y, _ = merge_data(Y) + _data_Y, _ = merge_data(Y) + data_Y = list(map(lambda y : self.mapping[y], _data_Y)) score = self.cls_list[0].score(X = data_X, y = data_Y) return score, [score] def train(self, X, Y): #self.label_lists = [] data_X, _ = merge_data(X) - data_Y, _ = merge_data(Y) + _data_Y, _ = merge_data(Y) + data_Y = list(map(lambda y : self.mapping[y], _data_Y)) self.cls_list[0].fit(X = data_X, y = data_Y) class DecisionTree(WABLBasicModel): @@ -139,8 +139,8 @@ class CNN(WABLBasicModel): #self.label_lists.append(sorted(list(set(data_Y)))) class MyModel(WABLBasicModel): - def __init__(self, base_model): - + def __init__(self, base_model, pseudo_label_list): + super(MyModel, self).__init__(pseudo_label_list) self.cls_list = [] self.cls_list.append(base_model) From 06247730c9e3c6fb2d85bac6245f17ee99e8bded Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 18 Nov 2022 12:58:52 +0800 Subject: [PATCH 035/601] Update example.py --- example.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/example.py b/example.py index 7eb8b03..65789e2 100644 --- a/example.py +++ b/example.py @@ -11,8 +11,6 @@ #================================================================# from utils.plog import logger -from models.wabl_models import DecisionTree, KNN -import pickle as pk import numpy as np import time import framework @@ -26,8 +24,6 @@ from models.wabl_models import MyModel from multiprocessing import Pool import os -from datasets.data_generator import generate_data_via_codes, code_generator -from collections import defaultdict from abducer.abducer_base import AbducerBase from abducer.kb import add_KB, hwf_KB from datasets.mnist_add.get_mnist_add import get_mnist_add @@ -49,27 +45,27 @@ def run_test(): recorder_file_path = f"{result_dir}/1116.pk"# - # words = code_generator(code_len, code_num, letter_num) - kb = add_KB() + # kb = add_KB() + kb = hwf_KB() abducer = AbducerBase(kb) recorder = logger() recorder.set_savefile("test.log") - train_X, train_Y, test_X, test_Y = get_mnist_add() - # train_X, train_Y, test_X, test_Y = get_hwf() + # train_X, train_Y, test_X, test_Y = get_mnist_add() + train_X, train_Y, test_X, test_Y = get_hwf() recorder = plog.ResultRecorder() - cls = LeNet5() + cls = LeNet5(num_classes=len(kb.pseudo_label_list), image_size=(train_X[0][0].shape[1:])) criterion = nn.CrossEntropyLoss(size_average=True) optimizer = torch.optim.Adam(cls.parameters(), lr=0.001, betas=(0.9, 0.99)) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - sign_list = list(range(10)) - base_model = BasicModel(cls, criterion, optimizer, device, Params(), sign_list, recorder=recorder) - model = MyModel(base_model) + + base_model = BasicModel(cls, criterion, optimizer, device, Params(), recorder=recorder) + model = MyModel(base_model, kb.pseudo_label_list) res = framework.train(model, abducer, train_X, train_Y, sample_num = 10000, verbose = 1) print(res) From dfaeb9f8d575515933b52943751153ec2761d831 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 18 Nov 2022 15:38:41 +0800 Subject: [PATCH 036/601] Update get_mnist_add.py --- datasets/mnist_add/get_mnist_add.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/datasets/mnist_add/get_mnist_add.py b/datasets/mnist_add/get_mnist_add.py index fcada50..1af834a 100644 --- a/datasets/mnist_add/get_mnist_add.py +++ b/datasets/mnist_add/get_mnist_add.py @@ -3,27 +3,39 @@ import torchvision from torch.utils.data import Dataset from torchvision.transforms import transforms -def get_data(file, img_dataset): +def get_data(file, img_dataset, get_pseudo_label): X = [] + if(get_pseudo_label): + Z = [] Y = [] with open(file) as f: for line in f: line = line.strip().split(' ') X.append([img_dataset[int(line[0])][0], img_dataset[int(line[1])][0]]) + if(get_pseudo_label): + Z.append([img_dataset[int(line[0])][1], img_dataset[int(line[1])][1]]) Y.append(int(line[2])) - return X, Y + + if(get_pseudo_label): + return X, Z, Y + else: + return X, None, Y -def get_mnist_add(): +def get_mnist_add(train = True, get_pseudo_label = False): transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081, ))]) img_dataset = torchvision.datasets.MNIST(root='./datasets/mnist_add/', train=True, download=True, transform=transform) - train_X, train_Y = get_data('./datasets/mnist_add/train_data.txt', img_dataset) - test_X, test_Y = get_data('./datasets/mnist_add/test_data.txt', img_dataset) + if(train): + file = './datasets/mnist_add/train_data.txt' + else: + file = './datasets/mnist_add/test_data.txt' + + return get_data(file, img_dataset, get_pseudo_label) - return train_X, train_Y, test_X, test_Y if __name__ == "__main__": - train_X, train_Y, test_X, test_Y = get_mnist_add() + train_X, train_Y = get_mnist_add(train = True) + test_X, test_Y = get_mnist_add(train = False) print(len(train_X), len(test_X)) print(train_X[0][0].shape, train_X[0][1].shape, train_Y[0]) From 649513bb79f76179124750934927dc5706ec853c Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 18 Nov 2022 15:39:03 +0800 Subject: [PATCH 037/601] Update get_hwf.py --- datasets/hwf/get_hwf.py | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/datasets/hwf/get_hwf.py b/datasets/hwf/get_hwf.py index cfd1666..f94f1a5 100644 --- a/datasets/hwf/get_hwf.py +++ b/datasets/hwf/get_hwf.py @@ -7,30 +7,45 @@ img_transform = transforms.Compose([ transforms.Normalize((0.5,), (1,)) ]) -def get_data(file, precision_num = 2): +def get_data(file, get_pseudo_label, precision_num = 2): X = [] + if(get_pseudo_label): + Z = [] Y = [] img_dir = './datasets/hwf/data/Handwritten_Math_Symbols/' with open(file) as f: data = json.load(f) for idx in range(len(data)): imgs = [] + imgs_pseudo_label = [] for img_path in data[idx]['img_paths']: img = Image.open(img_dir + img_path).convert('L') img = img_transform(img) imgs.append(img) - X.append(imgs) - Y.append(round(data[idx]['res'], precision_num)) - return X, Y + if(get_pseudo_label): + imgs_pseudo_label.append(img_path.split('/')[0]) + if(len(imgs) == 3): + X.append(imgs) + if(get_pseudo_label): + Z.append(imgs_pseudo_label) + Y.append(round(data[idx]['res'], precision_num)) + + if(get_pseudo_label): + return X, Z, Y + else: + return X, None, Y -def get_hwf(precision_num = 2): - train_X, train_Y = get_data('./datasets/hwf/data/expr_train.json', precision_num) - test_X, test_Y = get_data('./datasets/hwf/data/expr_test.json', precision_num) +def get_hwf(train = True, get_pseudo_label = False, precision_num = 2): + if(train): + file = './datasets/hwf/data/expr_train.json' + else: + file = './datasets/hwf/data/expr_test.json' - return train_X, train_Y, test_X, test_Y + return get_data(file, get_pseudo_label, precision_num) if __name__ == "__main__": - train_X, train_Y, test_X, test_Y = get_hwf() + train_X, train_Y = get_hwf(train = True) + test_X, test_Y = get_hwf(train = False) print(len(train_X), len(test_X)) print(len(train_X[0]), train_X[0][0].shape, train_Y[0]) From 35bdb8d01fe02bbfc49f58df7ceffedd65744093 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 18 Nov 2022 15:52:01 +0800 Subject: [PATCH 038/601] Update framework.py --- framework.py | 83 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 35 deletions(-) diff --git a/framework.py b/framework.py index 92a20b5..5479316 100644 --- a/framework.py +++ b/framework.py @@ -17,33 +17,41 @@ import numpy as np from utils.plog import INFO, DEBUG, clocker @clocker -def block_sample(X_bak, C_bak, sample_num, epoch_idx): - part_num = (len(X_bak) // sample_num) +def block_sample(X, Z, Y, sample_num, epoch_idx): + part_num = (len(X) // sample_num) if part_num == 0: part_num = 1 seg_idx = epoch_idx % part_num INFO("seg_idx:", seg_idx, ", part num:", part_num, ", data num:", len(X_bak)) - X = X_bak[sample_num * seg_idx: sample_num * (seg_idx + 1)] - # Y = Y_bak[sample_num * seg_idx: sample_num * (seg_idx + 1)] - C = C_bak[sample_num * seg_idx: sample_num * (seg_idx + 1)] + X = X[sample_num * seg_idx: sample_num * (seg_idx + 1)] + Z = Z[sample_num * seg_idx: sample_num * (seg_idx + 1)] + Y = Y[sample_num * seg_idx: sample_num * (seg_idx + 1)] - return X, C + return X, Z, Y -def get_taglist(self, Y): - tmp = [[str(x) for x in label] for label in Y] +def get_taglist(self, Z): + tmp = [[str(x) for x in label] for label in Z] tmp = sorted(list(set(tmp))) return tmp -@clocker -def result_statistics(C, pseudo_Y, logic_forward): +def get_abl_acc(Y, pseudo_Z, logic_forward): abl_acc = 0 - for tidx, (c, pseudo_y) in enumerate(zip(C, pseudo_Y)): - if(logic_forward(pseudo_y) == c): - abl_acc += 1 - + for y, pseudo_z in zip(Y, pseudo_Z): + if(logic_forward(pseudo_z) == y): + abl_acc += 1 + return abl_acc / len(Y) + +def get_char_acc(Z, pseudo_Z): + char_acc = 0 + char_num = 0 + for z, pseudo_z in zip(Z, pseudo_Z): + char_num += len(z) + for zidx in range(len(z)): + if(z[zidx] == pseudo_z[zidx]): + char_acc += 1 + return char_acc / char_num + - return abl_acc / len(C) - # def result_statistics(pseudo_Y, Y, abduced_Y): # abd_err_num = 0 @@ -89,14 +97,14 @@ def result_statistics(C, pseudo_Y, logic_forward): # return result @clocker -def filter_data(X, abduced_Y): - finetune_Y = [] +def filter_data(X, abduced_Z): + finetune_Z = [] finetune_X = [] - for abduced_x, abduced_y in zip(X, abduced_Y): - if abduced_y is not None: + for abduced_x, abduced_z in zip(X, abduced_Z): + if abduced_z is not None: finetune_X.append(abduced_x) - finetune_Y.append(abduced_y) - return finetune_X, finetune_Y + finetune_Z.append(abduced_z) + return finetune_X, finetune_Z @clocker def is_all_sublabel_exist(labels, std_label_list): @@ -112,42 +120,47 @@ def is_all_sublabel_exist(labels, std_label_list): return False return True -def pretrain(model, X, Y): +def pretrain(model, X, Z): pass -def train(model, abducer, X, C, epochs = 10, sample_num = -1, verbose = -1): +def train(model, abducer, X, Z, Y, epochs = 10, sample_num = -1, verbose = -1): # Set default parameters if sample_num == -1: sample_num = len(X) if verbose < 1: verbose = epochs + + char_acc_flag = 1 + if Z == None: + char_acc_flag = 0 + Z = [None] * len(X) predict_func = clocker(model.predict) train_func = clocker(model.train) abduce_func = clocker(abducer.batch_abduce) - X_bak = X - C_bak = C epochs = 50 + # Abductive learning train process for epoch_idx in range(epochs): - X, C = block_sample(X_bak, C_bak, sample_num, epoch_idx) + X, Z, Y = block_sample(X, Z, Y, sample_num, epoch_idx) preds_res = predict_func(X) - - abl_acc = result_statistics(C, preds_res['cls'], abducer.kb.logic_forward) - print('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc) - - abduced_Y = abduce_func(preds_res, C) - + abduced_Z = abduce_func(preds_res, Y) - finetune_X, finetune_Y = filter_data(X, abduced_Y) + abl_acc = get_abl_acc(Y, preds_res['cls'], abducer.kb.logic_forward) + if(not char_acc_flag): + ori_char_acc = get_char_acc(Z, preds_res['cls']) + abd_char_acc = get_char_acc(abduced_Z, preds_res['cls']) + print('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc, ' ori_char_acc:', ori_char_acc, ' abd_char_acc:', abd_char_acc) + finetune_X, finetune_Z = filter_data(X, abduced_Z) if len(finetune_X) > 0: - train_func(finetune_X, finetune_Y)#, n_epoch = 10) + train_func(finetune_X, finetune_Z) else: INFO("lack of data, all abduced failed", len(finetune_X)) + return abl_acc # def train(model, abducer, X, Y, C = None, epochs = 10, sample_num = -1, verbose = -1, check_sublabel = True): From b037edaf0b0eb82ad1d6c57e8ef50663474211ab Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 18 Nov 2022 16:03:17 +0800 Subject: [PATCH 039/601] Update framework.py --- framework.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/framework.py b/framework.py index 5479316..a37483b 100644 --- a/framework.py +++ b/framework.py @@ -22,7 +22,7 @@ def block_sample(X, Z, Y, sample_num, epoch_idx): if part_num == 0: part_num = 1 seg_idx = epoch_idx % part_num - INFO("seg_idx:", seg_idx, ", part num:", part_num, ", data num:", len(X_bak)) + INFO("seg_idx:", seg_idx, ", part num:", part_num, ", data num:", len(X)) X = X[sample_num * seg_idx: sample_num * (seg_idx + 1)] Z = Z[sample_num * seg_idx: sample_num * (seg_idx + 1)] Y = Y[sample_num * seg_idx: sample_num * (seg_idx + 1)] @@ -150,10 +150,12 @@ def train(model, abducer, X, Z, Y, epochs = 10, sample_num = -1, verbose = -1): abduced_Z = abduce_func(preds_res, Y) abl_acc = get_abl_acc(Y, preds_res['cls'], abducer.kb.logic_forward) - if(not char_acc_flag): + if(char_acc_flag): ori_char_acc = get_char_acc(Z, preds_res['cls']) abd_char_acc = get_char_acc(abduced_Z, preds_res['cls']) - print('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc, ' ori_char_acc:', ori_char_acc, ' abd_char_acc:', abd_char_acc) + print('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc, ' ori_char_acc:', ori_char_acc, ' abd_char_acc:', abd_char_acc) + else: + print('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc) finetune_X, finetune_Z = filter_data(X, abduced_Z) if len(finetune_X) > 0: From a8f33df3a306a4dbd98b6a290d9f23e3b75e28de Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 18 Nov 2022 16:03:54 +0800 Subject: [PATCH 040/601] Update example.py --- example.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/example.py b/example.py index 65789e2..14d2108 100644 --- a/example.py +++ b/example.py @@ -30,8 +30,8 @@ from datasets.mnist_add.get_mnist_add import get_mnist_add from datasets.hwf.get_hwf import get_hwf class Params: - imgH = 45 - imgW = 45 + imgH = 28 + imgW = 28 keep_ratio = True saveInterval = 10 batchSize = 16 @@ -45,17 +45,15 @@ def run_test(): recorder_file_path = f"{result_dir}/1116.pk"# - # kb = add_KB() - kb = hwf_KB() - abducer = AbducerBase(kb) + kb = add_KB() + # kb = hwf_KB() + abducer = AbducerBase(kb, 2) recorder = logger() recorder.set_savefile("test.log") - - # train_X, train_Y, test_X, test_Y = get_mnist_add() - train_X, train_Y, test_X, test_Y = get_hwf() - + train_X, train_Z, train_Y = get_mnist_add(train = True, get_pseudo_label = True) + test_X, test_Z, test_Y = get_mnist_add(train = False, get_pseudo_label = True) recorder = plog.ResultRecorder() cls = LeNet5(num_classes=len(kb.pseudo_label_list), image_size=(train_X[0][0].shape[1:])) @@ -67,7 +65,7 @@ def run_test(): base_model = BasicModel(cls, criterion, optimizer, device, Params(), recorder=recorder) model = MyModel(base_model, kb.pseudo_label_list) - res = framework.train(model, abducer, train_X, train_Y, sample_num = 10000, verbose = 1) + res = framework.train(model, abducer, train_X, train_Z, train_Y, sample_num = 10000, verbose = 1) print(res) From 24dcf02b33a822b0bd3a8bf3379ec7c22a5c1382 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Sat, 19 Nov 2022 09:51:37 +0800 Subject: [PATCH 041/601] Update kb.py --- abducer/kb.py | 229 +++++++++++++++----------------------------------- 1 file changed, 70 insertions(+), 159 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 12772e5..a448a83 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -44,12 +44,14 @@ class KBBase(ABC): def __len__(self): pass -class add_KB(KBBase): - def __init__(self, kb_max_len = -1): + +class ClsKB(KBBase): + def __init__(self, pseudo_label_list, kb_max_len = -1): super().__init__() - self.pseudo_label_list = list(range(10)) + self.pseudo_label_list = pseudo_label_list self.base = {} self.kb_max_len = kb_max_len + if(self.kb_max_len > 0): X = self.get_X(self.pseudo_label_list, self.kb_max_len) Y = self.get_Y(X, self.logic_forward) @@ -57,9 +59,6 @@ class add_KB(KBBase): for x, y in zip(X, Y): self.base.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) - def logic_forward(self, nums): - return sum(nums) - def get_X(self, pseudo_label_list, max_len): res = [] assert(max_len >= 2) @@ -69,6 +68,9 @@ class add_KB(KBBase): def get_Y(self, X, logic_forward): return [logic_forward(nums) for nums in X] + + def logic_forward(self): + return None def get_candidates(self, key, length = None): if(self.base == {}): @@ -76,7 +78,7 @@ class add_KB(KBBase): if key is None: return self.get_all_candidates() - + length = self._length(length) if(self.kb_max_len < min(length)): return [] @@ -84,163 +86,72 @@ class add_KB(KBBase): def get_all_candidates(self): return sum([sum(v.values(), []) for v in self.base.values()], []) - + def _dict_len(self, dic): return sum(len(c) for c in dic.values()) def __len__(self): return sum(self._dict_len(v) for v in self.base.values()) - -class hwf_KB(KBBase): + + + +class add_KB(ClsKB): def __init__(self, kb_max_len = -1): - super().__init__() - self.pseudo_label_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', '*', '/'] - self.base = {} - self.kb_max_len = kb_max_len - if(self.kb_max_len > 0): - X = self.get_X(self.pseudo_label_list, self.kb_max_len) - Y = self.get_Y(X, self.logic_forward) + self.pseudo_label_list = list(range(10)) + super().__init__(self.pseudo_label_list, kb_max_len) + + def logic_forward(self, nums): + return sum(nums) - for x, y in zip(X, Y): - self.base.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) + def get_candidates(self, key, length = None): + return super().get_candidates(key, length) - def calculate(self, formula): - stack = [] - postfix = [] - priority = {'+': 0, '-': 0, - '*': 1, '/': 1} - skip_flag = 0 - for i in range(len(formula)): - if formula[i] == '-': - if i == 0: - formula.insert(0, 0) - for i in range(len(formula)): - if skip_flag: - skip_flag -= 1 - continue - char = formula[i] - if char in priority.keys(): - while stack and (priority[char] <= priority[stack[-1]]): - postfix.append(stack.pop()) - stack.append(char) - else: - num = int(char) - while (i + 1) < len(formula): - if formula[i + 1] not in priority.keys(): - skip_flag += 1 - num = num * 10 + int(formula[i + 1]) - i += 1 - else: - break - postfix.append(num) - while stack: - postfix.append(stack.pop()) + def get_all_candidates(self): + return super().get_all_candidates() + + def _dict_len(self, dic): + return super()._dict_len(dic) - for i in postfix: - if i in priority.keys(): - num2 = stack.pop() - num1 = stack.pop() - if i == '+': - res = num1 + num2 - elif i == '-': - res = num1 - num2 - elif i == '*': - res = num1 * num2 - elif i == '/': - if(num2 == 0): - return np.inf - res = num1 / num2 - stack.append(res) - else: - stack.append(i) - return round(stack[0], 2) + def __len__(self): + return super().__len__() +class hwf_KB(ClsKB): + def __init__(self, kb_max_len = -1): + self.pseudo_label_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', '*', '/'] + super().__init__(self.pseudo_label_list, kb_max_len) + def valid_formula(self, formula): - symbol_idx_list = [] - for idx, c in enumerate(formula): - if(idx == 0 and c == '-'): - if(len(formula) == 1 or formula[1] in ['+', '-', '*', '/']): - return False - continue - if(c in ['+', '-', '*', '/']): - if(idx - 1 in symbol_idx_list): - return False - symbol_idx_list.append(idx) - if(0 in symbol_idx_list or len(formula) - 1 in symbol_idx_list): + if(len(formula) % 2 == 0): return False + for i in range(len(formula)): + if(i % 2 == 0 and formula[i] not in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']): + return False + if(i % 2 != 0 and formula[i] not in ['+', '-', '*', '/']): + return False return True def logic_forward(self, formula): if(self.valid_formula(formula) == False): return np.inf - return self.calculate(list(formula)) + try: + return eval(''.join(formula)) + except ZeroDivisionError: + return np.inf - def get_X(self, pseudo_label_list, max_len): - res = [] - assert(max_len >= 2) - for len in range(2, max_len + 1): - res += list(product(pseudo_label_list, repeat = len)) - return res - - def get_Y(self, X, logic_forward): - return [logic_forward(formula) for formula in X] - def get_candidates(self, key, length = None): - if(self.base == {}): - return [] - - if key is None: - return self.get_all_candidates() - - length = self._length(length) - if(self.kb_max_len < min(length)): - return [] - return sum([self.base[l][key] for l in length], []) + return super().get_candidates(key, length) def get_all_candidates(self): - return sum([sum(v.values(), []) for v in self.base.values()], []) - - def _dict_len(self, dic): - return sum(len(c) for c in dic.values()) - - def __len__(self): - return sum(self._dict_len(v) for v in self.base.values()) - -class cls_KB(KBBase): - def __init__(self, X, Y = None): - super().__init__() - self.base = {} - - if X is None: - return - - if Y is None: - Y = [None] * len(X) - - for x, y in zip(X, Y): - self.base.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) + return super().get_all_candidates() - def logic_forward(self): - return None - - def get_candidates(self, key, length = None): - if key is None: - return self.get_all_candidates() - - length = self._length(length) - - return sum([self.base[l][key] for l in length], []) - - def get_all_candidates(self): - return sum([sum(v.values(), []) for v in self.base.values()], []) - def _dict_len(self, dic): - return sum(len(c) for c in dic.values()) + return super()._dict_len(dic) def __len__(self): - return sum(self._dict_len(v) for v in self.base.values()) + return super().__len__() + -class reg_KB(KBBase): +class RegKB(KBBase): def __init__(self, X, Y = None): super().__init__() tmp_dict = {} @@ -323,26 +234,26 @@ if __name__ == "__main__": print() - X = ["1+1", "0+1", "1+0", "2+0", "1+0+1"] - Y = [2, 1, 1, 2, 2] - kb = cls_KB(X, Y) - print('len(kb):', len(kb)) - res = kb.get_candidates(2, 5) - print(res) - res = kb.get_candidates(2, 3) - print(res) - res = kb.get_candidates(None) - print(res) - print() + # X = ["1+1", "0+1", "1+0", "2+0", "1+0+1"] + # Y = [2, 1, 1, 2, 2] + # kb = ClsKB(X, Y) + # print('len(kb):', len(kb)) + # res = kb.get_candidates(2, 5) + # print(res) + # res = kb.get_candidates(2, 3) + # print(res) + # res = kb.get_candidates(None) + # print(res) + # print() - X = ["1+1", "0+1", "1+0", "2+0", "1+0.5", "0.75+0.75"] - Y = [2, 1, 1, 2, 1.5, 1.5] - kb = reg_KB(X, Y) - print('len(kb):', len(kb)) - res = kb.get_candidates(1.6) - print(res) - res = kb.get_candidates(1.6, length = 9) - print(res) - res = kb.get_candidates(None) - print(res) + # X = ["1+1", "0+1", "1+0", "2+0", "1+0.5", "0.75+0.75"] + # Y = [2, 1, 1, 2, 1.5, 1.5] + # kb = RegKB(X, Y) + # print('len(kb):', len(kb)) + # res = kb.get_candidates(1.6) + # print(res) + # res = kb.get_candidates(1.6, length = 9) + # print(res) + # res = kb.get_candidates(None) + # print(res) From 5224c86035d29cbf769aade41b7f0db510671172 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Sat, 19 Nov 2022 10:09:36 +0800 Subject: [PATCH 042/601] Update kb.py --- abducer/kb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abducer/kb.py b/abducer/kb.py index a448a83..85c7519 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -134,7 +134,7 @@ class hwf_KB(ClsKB): if(self.valid_formula(formula) == False): return np.inf try: - return eval(''.join(formula)) + return round(eval(''.join(formula)), 2) except ZeroDivisionError: return np.inf From cf33651a7ade6cf1f68698a7ece95cc96ce72cc3 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Sat, 19 Nov 2022 10:25:51 +0800 Subject: [PATCH 043/601] Update abducer_base.py --- abducer/abducer_base.py | 51 +++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 23019b8..af9fdc8 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -38,34 +38,29 @@ def confidence_dist(A, B): class AbducerBase(abc.ABC): - def __init__(self, kb, dist_func = 'hamming', pred_res_parse = None, cache = True): + def __init__(self, kb, dist_func = 'confidence', cache = True): self.kb = kb - - if(dist_func == 'hamming'): - self.dist_func = hamming_dist - elif(dist_func == 'confidence'): - self.dist_func = confidence_dist - - if pred_res_parse is None: - if(dist_func == 'hamming'): - pred_res_parse = lambda x : x["cls"] - elif dist_func == 'confidence': - pred_res_parse = lambda x : x["prob"] - self.pred_res_parse = pred_res_parse - + assert(dist_func == 'hamming' or dist_func == 'confidence') + self.dist_func = dist_func self.cache = cache self.cache_min_address_num = {} self.cache_candidates = {} - def get_min_cost_candidate(self, pred_res, candidates): - cost_list = self.dist_func(pred_res, candidates) + def get_cost_list(self, pred_res, pred_res_prob, candidates): + if(self.dist_func == 'hamming'): + return hamming_dist(pred_res, candidates) + elif(self.dist_func == 'confidence'): + return confidence_dist(pred_res_prob, candidates) + + def get_min_cost_candidate(self, pred_res, pred_res_prob, candidates): + cost_list = self.get_cost_list(pred_res, pred_res_prob, candidates) min_address_num = np.min(cost_list) idxs = np.where(cost_list == min_address_num)[0] return [candidates[idx] for idx in idxs][0] def abduce(self, data, max_address_num = -1, require_more_address = 0): - pred_res, ans = data - + pred_res, pred_res_prob, ans = data + if max_address_num == -1: max_address_num = len(pred_res) @@ -74,12 +69,12 @@ class AbducerBase(abc.ABC): if((tuple(pred_res), ans, address_num) in self.cache_candidates): # print('cached') candidates = self.cache_candidates[(tuple(pred_res), ans, address_num)] - candidates = self.get_min_cost_candidate(pred_res, candidates) + candidates = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) return candidates if(self.kb.base != {}): all_candidates = self.kb.get_candidates(ans, len(pred_res)) - cost_list = self.dist_func(pred_res, all_candidates) + cost_list = self.get_cost_list(pred_res, pred_res_prob, all_candidates) min_address_num = np.min(cost_list) address_num = min(max_address_num, min_address_num + require_more_address) idxs = np.where(cost_list <= address_num)[0] @@ -92,7 +87,7 @@ class AbducerBase(abc.ABC): self.cache_min_address_num[(tuple(pred_res), ans)] = min_address_num self.cache_candidates[(tuple(pred_res), ans, address_num)] = candidates - candidates = self.get_min_cost_candidate(pred_res, candidates) + candidates = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) return candidates def address(self, address_num, pred_res, key): @@ -136,18 +131,18 @@ class AbducerBase(abc.ABC): return candidates, min_address_num, address_num - def batch_abduce(self, Y, C, max_address_num = -1, require_more_address = 0): + def batch_abduce(self, Z, Y, max_address_num = -1, require_more_address = 0): return [ - self.abduce((y, c), max_address_num, require_more_address)\ - for y, c in zip(self.pred_res_parse(Y), C) + self.abduce((z, prob, y), max_address_num, require_more_address)\ + for z, prob, y in zip(Z['cls'], Z['prob'], Y) ] - def __call__(self, Y, C, max_address_num = -1, require_more_address = 0): - return self.batch_abduce(Y, C, max_address_num, require_more_address) + def __call__(self, Z, Y, max_address_num = -1, require_more_address = 0): + return self.batch_abduce(Z, Y, max_address_num, require_more_address) -if __name__ == "__main__": +if __name__ == '__main__': kb = add_KB() abd = AbducerBase(kb) res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 0) @@ -166,7 +161,7 @@ if __name__ == "__main__": abd = AbducerBase(kb) res = abd.abduce((['5', '+', '2'], 3), max_address_num = 2, require_more_address = 0) print(res) - res = abd.abduce((['5', '+', '2'], 1.67), max_address_num = 2, require_more_address = 0) + res = abd.abduce((['5', '+', '2'], 1.67), max_address_num = 3, require_more_address = 0) print(res) res = abd.abduce((['5', '+', '3'], 0.33), max_address_num = 3, require_more_address = 3) print(res) From 36304c98dc8af74cf8c7ab51fbc8d9ddf18cb03a Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Sat, 19 Nov 2022 10:42:26 +0800 Subject: [PATCH 044/601] Update abducer_base.py --- abducer/abducer_base.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index af9fdc8..c94bca4 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -144,25 +144,25 @@ class AbducerBase(abc.ABC): if __name__ == '__main__': kb = add_KB() - abd = AbducerBase(kb) - res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 0) + abd = AbducerBase(kb, 'hamming') + res = abd.abduce(([1, 1, 1], None, 4), max_address_num = 2, require_more_address = 0) print(res) - res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 1) + res = abd.abduce(([1, 1, 1], None, 4), max_address_num = 2, require_more_address = 1) print(res) - res = abd.abduce(([1, 1, 1], 4), max_address_num = 1, require_more_address = 1) + res = abd.abduce(([1, 1, 1], None, 4), max_address_num = 1, require_more_address = 1) print(res) - res = abd.abduce(([1, 1, 1], 4), max_address_num = 2, require_more_address = 0) + res = abd.abduce(([1, 1, 1], None, 4), max_address_num = 2, require_more_address = 0) print(res) - res = abd.abduce(([1, 1, 1], 5), max_address_num = 2, require_more_address = 1) + res = abd.abduce(([1, 1, 1], None, 5), max_address_num = 2, require_more_address = 1) print(res) print() kb = hwf_KB() abd = AbducerBase(kb) - res = abd.abduce((['5', '+', '2'], 3), max_address_num = 2, require_more_address = 0) + res = abd.abduce((['5', '+', '2'], None, 3), max_address_num = 2, require_more_address = 0) print(res) - res = abd.abduce((['5', '+', '2'], 1.67), max_address_num = 3, require_more_address = 0) + res = abd.abduce((['5', '+', '2'], None, 1.67), max_address_num = 3, require_more_address = 0) print(res) - res = abd.abduce((['5', '+', '3'], 0.33), max_address_num = 3, require_more_address = 3) + res = abd.abduce((['5', '+', '3'], None, 0.33), max_address_num = 3, require_more_address = 3) print(res) print() From 65e3b93912bc436d0138cadbe99549f67d43c5d5 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Sat, 19 Nov 2022 13:56:47 +0800 Subject: [PATCH 045/601] Update example.py --- example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example.py b/example.py index 14d2108..1a20b28 100644 --- a/example.py +++ b/example.py @@ -36,7 +36,7 @@ class Params: saveInterval = 10 batchSize = 16 workers = 16 - n_epoch = 10 + n_epoch = 1 stop_loss = None def run_test(): From 90c5703b57477805a9f4de700128e26cba57ecf6 Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Sat, 19 Nov 2022 23:58:27 +0800 Subject: [PATCH 046/601] update basic_model.py and wabl_models.py --- models/basic_model.py | 48 ++++++++++++++++++++++++------------------- models/wabl_models.py | 11 ++++------ 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/models/basic_model.py b/models/basic_model.py index e251ec4..86fbea5 100644 --- a/models/basic_model.py +++ b/models/basic_model.py @@ -42,7 +42,7 @@ class XYDataset(Dataset): if self.target_transform is not None: label = self.target_transform(label) - return (img, label, index) + return (img, label) class FakeRecorder(): def __init__(self): @@ -57,14 +57,24 @@ class BasicModel(): criterion, optimizer, device, - params, + batch_size = 1, + num_epochs = 10, + stop_loss = 0.01, + num_workers = 0, + save_interval = None, + save_dir = None, transform = None, - target_transform=None, + target_transform = None, collate_fn = None, recorder = None): self.model = model.to(device) + self.batch_size = batch_size + self.num_epochs = num_epochs + self.stop_loss = stop_loss + self.num_workers = num_workers + self.criterion = criterion self.optimizer = optimizer self.transform = transform @@ -75,8 +85,8 @@ class BasicModel(): recorder = FakeRecorder() self.recorder = recorder - self.save_interval = params.saveInterval - self.params = params + self.save_interval = save_interval + self.save_dir = save_dir self.collate_fn = collate_fn pass @@ -91,9 +101,9 @@ class BasicModel(): if loss_value < min_loss: min_loss = loss_value if epoch > 0 and self.save_interval is not None and epoch % self.save_interval == 0: - assert hasattr(self.params, 'save_dir') - self.save(self.params.save_dir) - if stop_loss is not None and loss_value < stop_loss: + assert self.save_dir is not None + self.save(self.save_dir) + if stop_loss is not None and loss_value < stop_loss: break recorder.print("Model fitted, minimal loss is ", min_loss) return loss_value @@ -102,17 +112,16 @@ class BasicModel(): X = None, y = None): if data_loader is None: - params = self.params collate_fn = self.collate_fn transform = self.transform target_transform = self.target_transform train_dataset = XYDataset(X, y, transform=transform, target_transform=target_transform) sampler = None - data_loader = torch.utils.data.DataLoader(train_dataset, batch_size=params.batchSize, \ - shuffle=True, sampler=sampler, num_workers=int(params.workers), \ + data_loader = torch.utils.data.DataLoader(train_dataset, batch_size=self.batch_size, \ + shuffle=True, sampler=sampler, num_workers=int(self.num_workers), \ collate_fn=collate_fn) - return self._fit(data_loader, params.n_epoch, params.stop_loss) + return self._fit(data_loader, self.num_epochs, self.stop_loss) def train_epoch(self, data_loader): model = self.model @@ -155,7 +164,6 @@ class BasicModel(): def predict(self, data_loader = None, X = None, print_prefix = ""): if data_loader is None: - params = self.params collate_fn = self.collate_fn transform = self.transform target_transform = self.target_transform @@ -163,8 +171,8 @@ class BasicModel(): Y = [0] * len(X) val_dataset = XYDataset(X, Y, transform=transform, target_transform=target_transform) sampler = None - data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=params.batchSize, \ - shuffle=False, sampler=sampler, num_workers=int(params.workers), \ + data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=self.batch_size, \ + shuffle=False, sampler=sampler, num_workers=int(self.num_workers), \ collate_fn=collate_fn) recorder = self.recorder @@ -174,7 +182,6 @@ class BasicModel(): def predict_proba(self, data_loader = None, X = None, print_prefix = ""): if data_loader is None: - params = self.params collate_fn = self.collate_fn transform = self.transform target_transform = self.target_transform @@ -182,8 +189,8 @@ class BasicModel(): Y = [0] * len(X) val_dataset = XYDataset(X, Y, transform=transform, target_transform=target_transform) sampler = None - data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=params.batchSize, \ - shuffle=False, sampler=sampler, num_workers=int(params.workers), \ + data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=self.batch_size, \ + shuffle=False, sampler=sampler, num_workers=int(self.num_workers), \ collate_fn=collate_fn) recorder = self.recorder @@ -222,15 +229,14 @@ class BasicModel(): def val(self, data_loader = None, X = None, y = None, print_prefix = ""): if data_loader is None: - params = self.params collate_fn = self.collate_fn transform = self.transform target_transform = self.target_transform val_dataset = XYDataset(X, y, transform=transform, target_transform=target_transform) sampler = None - data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=params.batchSize, \ - shuffle=True, sampler=sampler, num_workers=int(params.workers), \ + data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=self.batch_size, \ + shuffle=True, sampler=sampler, num_workers=int(self.num_workers), \ collate_fn=collate_fn) return self._val(data_loader, print_prefix) diff --git a/models/wabl_models.py b/models/wabl_models.py index 5d44719..b854039 100644 --- a/models/wabl_models.py +++ b/models/wabl_models.py @@ -49,7 +49,10 @@ def reshape_data(Y, marks): class WABLBasicModel: - def __init__(self, pseudo_label_list): + def __init__(self, base_model, pseudo_label_list): + self.cls_list = [] + self.cls_list.append(base_model) + self.pseudo_label_list = pseudo_label_list self.mapping = dict(zip(pseudo_label_list, list(range(len(pseudo_label_list))))) self.remapping = dict(zip(list(range(len(pseudo_label_list))), pseudo_label_list)) @@ -138,12 +141,6 @@ class CNN(WABLBasicModel): self.cls_list[i].fit(data_X, data_Y) #self.label_lists.append(sorted(list(set(data_Y)))) -class MyModel(WABLBasicModel): - def __init__(self, base_model, pseudo_label_list): - super(MyModel, self).__init__(pseudo_label_list) - self.cls_list = [] - self.cls_list.append(base_model) - if __name__ == "__main__": #data_path = "utils/hamming_data/generated_data/hamming_7_3_0.20.pk" data_path = "datasets/generated_data/0_code_7_2_0.00.pk" From 40a3889c68dd4472007ea96d193eec52711098d6 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Sun, 20 Nov 2022 22:01:50 +0800 Subject: [PATCH 047/601] Update abducer_base.py --- abducer/abducer_base.py | 51 ++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index c94bca4..bbf00fa 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -17,23 +17,7 @@ import numpy as np from itertools import product, combinations -def hamming_dist(A, B): - B = np.array(B) - A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) - return np.sum(A != B, axis = 1) -def confidence_dist(A, B): - B = np.array(B) - - #print(A) - A = np.clip(A, 1e-9, 1) - A = np.expand_dims(A, axis=0) - A = A.repeat(axis=0, repeats=(len(B))) - rows = np.array(range(len(B))) - rows = np.expand_dims(rows, axis = 1).repeat(axis = 1, repeats = len(B[0])) - cols = np.array(range(len(B[0]))) - cols = np.expand_dims(cols, axis = 0).repeat(axis = 0, repeats = len(B)) - return 1 - np.prod(A[rows, cols, B], axis = 1) @@ -46,11 +30,31 @@ class AbducerBase(abc.ABC): self.cache_min_address_num = {} self.cache_candidates = {} + def hamming_dist(self, A, B): + B = np.array(B) + A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) + return np.sum(A != B, axis = 1) + + def confidence_dist(self, A, B): + mapping = dict(zip(self.kb.pseudo_label_list, list(range(len(self.kb.pseudo_label_list))))) + B = [list(map(lambda x : mapping[x], b)) for b in B] + + B = np.array(B) + A = np.clip(A, 1e-9, 1) + A = np.expand_dims(A, axis=0) + A = A.repeat(axis=0, repeats=(len(B))) + rows = np.array(range(len(B))) + rows = np.expand_dims(rows, axis = 1).repeat(axis = 1, repeats = len(B[0])) + cols = np.array(range(len(B[0]))) + cols = np.expand_dims(cols, axis = 0).repeat(axis = 0, repeats = len(B)) + return 1 - np.prod(A[rows, cols, B], axis = 1) + + def get_cost_list(self, pred_res, pred_res_prob, candidates): if(self.dist_func == 'hamming'): - return hamming_dist(pred_res, candidates) + return self.hamming_dist(pred_res, candidates) elif(self.dist_func == 'confidence'): - return confidence_dist(pred_res_prob, candidates) + return self.confidence_dist(pred_res_prob, candidates) def get_min_cost_candidate(self, pred_res, pred_res_prob, candidates): cost_list = self.get_cost_list(pred_res, pred_res_prob, candidates) @@ -60,7 +64,6 @@ class AbducerBase(abc.ABC): def abduce(self, data, max_address_num = -1, require_more_address = 0): pred_res, pred_res_prob, ans = data - if max_address_num == -1: max_address_num = len(pred_res) @@ -69,12 +72,12 @@ class AbducerBase(abc.ABC): if((tuple(pred_res), ans, address_num) in self.cache_candidates): # print('cached') candidates = self.cache_candidates[(tuple(pred_res), ans, address_num)] - candidates = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) - return candidates + candidate = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) + return candidate if(self.kb.base != {}): all_candidates = self.kb.get_candidates(ans, len(pred_res)) - cost_list = self.get_cost_list(pred_res, pred_res_prob, all_candidates) + cost_list = self.hamming_dist(pred_res, all_candidates) min_address_num = np.min(cost_list) address_num = min(max_address_num, min_address_num + require_more_address) idxs = np.where(cost_list <= address_num)[0] @@ -87,8 +90,8 @@ class AbducerBase(abc.ABC): self.cache_min_address_num[(tuple(pred_res), ans)] = min_address_num self.cache_candidates[(tuple(pred_res), ans, address_num)] = candidates - candidates = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) - return candidates + candidate = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) + return candidate def address(self, address_num, pred_res, key): new_candidates = [] From fad85240a2223c205b524c2701e317231f4ff694 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Sun, 20 Nov 2022 22:06:49 +0800 Subject: [PATCH 048/601] Update kb.py --- abducer/kb.py | 62 +++++++++++++++++---------------------------------- 1 file changed, 21 insertions(+), 41 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 85c7519..54a367e 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -46,23 +46,21 @@ class KBBase(ABC): class ClsKB(KBBase): - def __init__(self, pseudo_label_list, kb_max_len = -1): + def __init__(self, pseudo_label_list, len_list = None): super().__init__() self.pseudo_label_list = pseudo_label_list self.base = {} - self.kb_max_len = kb_max_len + self.len_list = len_list - if(self.kb_max_len > 0): - X = self.get_X(self.pseudo_label_list, self.kb_max_len) + if(self.len_list != None): + X = self.get_X(self.pseudo_label_list, self.len_list) Y = self.get_Y(X, self.logic_forward) - for x, y in zip(X, Y): self.base.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) - def get_X(self, pseudo_label_list, max_len): + def get_X(self, pseudo_label_list, len_list): res = [] - assert(max_len >= 2) - for len in range(2, max_len + 1): + for len in len_list: res += list(product(pseudo_label_list, repeat = len)) return res @@ -80,7 +78,7 @@ class ClsKB(KBBase): return self.get_all_candidates() length = self._length(length) - if(self.kb_max_len < min(length)): + if(max(self.len_list) < min(length)): return [] return sum([self.base[l][key] for l in length], []) @@ -96,29 +94,18 @@ class ClsKB(KBBase): class add_KB(ClsKB): - def __init__(self, kb_max_len = -1): + def __init__(self, len_list = None): self.pseudo_label_list = list(range(10)) - super().__init__(self.pseudo_label_list, kb_max_len) + super().__init__(self.pseudo_label_list, len_list) def logic_forward(self, nums): return sum(nums) - - def get_candidates(self, key, length = None): - return super().get_candidates(key, length) - - def get_all_candidates(self): - return super().get_all_candidates() - def _dict_len(self, dic): - return super()._dict_len(dic) - - def __len__(self): - return super().__len__() class hwf_KB(ClsKB): - def __init__(self, kb_max_len = -1): + def __init__(self, len_list = None): self.pseudo_label_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', '*', '/'] - super().__init__(self.pseudo_label_list, kb_max_len) + super().__init__(self.pseudo_label_list, len_list) def valid_formula(self, formula): if(len(formula) % 2 == 0): @@ -137,18 +124,6 @@ class hwf_KB(ClsKB): return round(eval(''.join(formula)), 2) except ZeroDivisionError: return np.inf - - def get_candidates(self, key, length = None): - return super().get_candidates(key, length) - - def get_all_candidates(self): - return super().get_all_candidates() - - def _dict_len(self, dic): - return super()._dict_len(dic) - - def __len__(self): - return super().__len__() class RegKB(KBBase): @@ -198,17 +173,18 @@ class RegKB(KBBase): def __len__(self): return sum([sum(len(x) for x in D[0]) for D in self.base.values()]) +import time if __name__ == "__main__": # With ground KB - kb = add_KB(kb_max_len = 5) + kb = add_KB(len_list = [2]) print('len(kb):', len(kb)) res = kb.get_candidates(0) print(res) - res = kb.get_candidates(18, length = 2) + res = kb.get_candidates(18) print(res) - res = kb.get_candidates(18, length = 8) + res = kb.get_candidates(18) print(res) - res = kb.get_candidates(7, length = 3) + res = kb.get_candidates(7) print(res) print() @@ -225,8 +201,12 @@ if __name__ == "__main__": print(res) print() - kb = hwf_KB(kb_max_len = 5) + start = time.time() + kb = hwf_KB(len_list = [1, 3, 5, 7]) + print(time.time() - start) print('len(kb):', len(kb)) + res = kb.get_candidates(2, length = 1) + print(res) res = kb.get_candidates(1, length = 3) print(res) res = kb.get_candidates(3.67, length = 5) From 1a38478bda69a51e23136a04eaada3fb439e93e1 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 21 Nov 2022 09:30:30 +0800 Subject: [PATCH 049/601] Update kb.py --- abducer/kb.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 54a367e..a934ad8 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -77,9 +77,9 @@ class ClsKB(KBBase): if key is None: return self.get_all_candidates() - length = self._length(length) - if(max(self.len_list) < min(length)): + if (type(length) is int and length not in self.len_list): return [] + length = self._length(length) return sum([self.base[l][key] for l in length], []) def get_all_candidates(self): @@ -94,7 +94,7 @@ class ClsKB(KBBase): class add_KB(ClsKB): - def __init__(self, len_list = None): + def __init__(self, len_list = [2]): self.pseudo_label_list = list(range(10)) super().__init__(self.pseudo_label_list, len_list) @@ -103,7 +103,7 @@ class add_KB(ClsKB): class hwf_KB(ClsKB): - def __init__(self, len_list = None): + def __init__(self, len_list = [1, 3, 5, 7]): self.pseudo_label_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', '*', '/'] super().__init__(self.pseudo_label_list, len_list) From 15eda317bcf53bf2ecb15ca6096baceed0de1593 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 21 Nov 2022 09:46:31 +0800 Subject: [PATCH 050/601] Update kb.py --- abducer/kb.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index a934ad8..98ea9bc 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -19,7 +19,7 @@ from collections import defaultdict from itertools import product class KBBase(ABC): - def __init__(self): + def __init__(self, GKB_flag = False): pass @abstractmethod @@ -46,13 +46,13 @@ class KBBase(ABC): class ClsKB(KBBase): - def __init__(self, pseudo_label_list, len_list = None): + def __init__(self, GKB_flag = False, pseudo_label_list = None, len_list = None): super().__init__() self.pseudo_label_list = pseudo_label_list self.base = {} self.len_list = len_list - if(self.len_list != None): + if GKB_flag: X = self.get_X(self.pseudo_label_list, self.len_list) Y = self.get_Y(X, self.logic_forward) for x, y in zip(X, Y): @@ -94,18 +94,18 @@ class ClsKB(KBBase): class add_KB(ClsKB): - def __init__(self, len_list = [2]): + def __init__(self, GKB_flag = False, len_list = [2]): self.pseudo_label_list = list(range(10)) - super().__init__(self.pseudo_label_list, len_list) + super().__init__(GKB_flag, self.pseudo_label_list, len_list) def logic_forward(self, nums): return sum(nums) class hwf_KB(ClsKB): - def __init__(self, len_list = [1, 3, 5, 7]): + def __init__(self, GKB_flag = False, len_list = [1, 3, 5, 7]): self.pseudo_label_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', '*', '/'] - super().__init__(self.pseudo_label_list, len_list) + super().__init__(GKB_flag, self.pseudo_label_list, len_list) def valid_formula(self, formula): if(len(formula) % 2 == 0): @@ -127,7 +127,7 @@ class hwf_KB(ClsKB): class RegKB(KBBase): - def __init__(self, X, Y = None): + def __init__(self, GKB_flag = False, X = None, Y = None): super().__init__() tmp_dict = {} for x, y in zip(X, Y): @@ -176,7 +176,7 @@ class RegKB(KBBase): import time if __name__ == "__main__": # With ground KB - kb = add_KB(len_list = [2]) + kb = add_KB(GKB_flag = True) print('len(kb):', len(kb)) res = kb.get_candidates(0) print(res) @@ -202,7 +202,7 @@ if __name__ == "__main__": print() start = time.time() - kb = hwf_KB(len_list = [1, 3, 5, 7]) + kb = hwf_KB(GKB_flag = True) print(time.time() - start) print('len(kb):', len(kb)) res = kb.get_candidates(2, length = 1) From bc8a72c21dad1289b307e1ee49787cc3762fa15f Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Mon, 21 Nov 2022 14:47:42 +0800 Subject: [PATCH 051/601] update readme --- README => readme.md | 9 +++++++++ 1 file changed, 9 insertions(+) rename README => readme.md (66%) diff --git a/README b/readme.md similarity index 66% rename from README rename to readme.md index 0aa2a11..1a9ebf1 100644 --- a/README +++ b/readme.md @@ -22,3 +22,12 @@ python share_example.py ## NOTICE They can only be used for academic purpose. For other purposes, please contact with LAMDA Group(www.lamda.nju.edu.cn). +## To do list + +- Improve speed and accuracy +- Add comparison with DeepProbLog, NGS,... (Accuracy and Speed) +- Add Inference/Abduction example with FOL engine (e.g., Prolog) +- Add zoopt optimization +- Rearrange structure and make it a python package +- Documents + From 0242e44c09f7e46532bc87c362a5141c36fb8ff7 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 21 Nov 2022 14:56:35 +0800 Subject: [PATCH 052/601] Update kb.py --- abducer/kb.py | 49 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 98ea9bc..c206f62 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -19,7 +19,7 @@ from collections import defaultdict from itertools import product class KBBase(ABC): - def __init__(self, GKB_flag = False): + def __init__(self): pass @abstractmethod @@ -31,7 +31,11 @@ class KBBase(ABC): pass @abstractmethod - def logic_forward(self, X): + def logic_forward(self): + pass + + @abstractmethod + def valid_candidate(self): pass def _length(self, length): @@ -48,27 +52,34 @@ class KBBase(ABC): class ClsKB(KBBase): def __init__(self, GKB_flag = False, pseudo_label_list = None, len_list = None): super().__init__() + self.GKB_flag = GKB_flag self.pseudo_label_list = pseudo_label_list self.base = {} self.len_list = len_list if GKB_flag: - X = self.get_X(self.pseudo_label_list, self.len_list) - Y = self.get_Y(X, self.logic_forward) + X, Y = self.get_GKB(self.pseudo_label_list, self.len_list) for x, y in zip(X, Y): self.base.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) - def get_X(self, pseudo_label_list, len_list): - res = [] + def get_GKB(self, pseudo_label_list, len_list): + all_X = [] for len in len_list: - res += list(product(pseudo_label_list, repeat = len)) - return res - - def get_Y(self, X, logic_forward): - return [logic_forward(nums) for nums in X] + all_X += list(product(pseudo_label_list, repeat = len)) + + X = [] + Y = [] + for x in all_X: + if self.valid_candidate(x): + X.append(x) + Y.append(self.logic_forward(x)) + return X, Y + + def valid_candidate(self): + pass def logic_forward(self): - return None + pass def get_candidates(self, key, length = None): if(self.base == {}): @@ -92,11 +103,13 @@ class ClsKB(KBBase): return sum(self._dict_len(v) for v in self.base.values()) - class add_KB(ClsKB): def __init__(self, GKB_flag = False, len_list = [2]): self.pseudo_label_list = list(range(10)) super().__init__(GKB_flag, self.pseudo_label_list, len_list) + + def valid_candidate(self, x): + return True def logic_forward(self, nums): return sum(nums) @@ -107,7 +120,7 @@ class hwf_KB(ClsKB): self.pseudo_label_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', '*', '/'] super().__init__(GKB_flag, self.pseudo_label_list, len_list) - def valid_formula(self, formula): + def valid_candidate(self, formula): if(len(formula) % 2 == 0): return False for i in range(len(formula)): @@ -118,7 +131,7 @@ class hwf_KB(ClsKB): return True def logic_forward(self, formula): - if(self.valid_formula(formula) == False): + if(self.valid_candidate(formula) == False): return np.inf try: return round(eval(''.join(formula)), 2) @@ -140,8 +153,12 @@ class RegKB(KBBase): Y = [y for y, x in data] self.base[l] = (X, Y) + def valid_candidate(self): + pass + def logic_forward(self): - return None + pass + def get_candidates(self, key, length = None): if key is None: From d544ccd3c12fefcbaebf0cee867409c48a290348 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 21 Nov 2022 14:56:54 +0800 Subject: [PATCH 053/601] Update abducer_base.py --- abducer/abducer_base.py | 55 ++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index bbf00fa..6de9987 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -11,16 +11,12 @@ #================================================================# import abc -# from kb import add_KB, hwf_KB -from abducer.kb import add_KB, hwf_KB +from kb import add_KB, hwf_KB +# from abducer.kb import add_KB, hwf_KB import numpy as np from itertools import product, combinations - - - - class AbducerBase(abc.ABC): def __init__(self, kb, dist_func = 'confidence', cache = True): self.kb = kb @@ -57,10 +53,15 @@ class AbducerBase(abc.ABC): return self.confidence_dist(pred_res_prob, candidates) def get_min_cost_candidate(self, pred_res, pred_res_prob, candidates): - cost_list = self.get_cost_list(pred_res, pred_res_prob, candidates) - min_address_num = np.min(cost_list) - idxs = np.where(cost_list == min_address_num)[0] - return [candidates[idx] for idx in idxs][0] + if(len(candidates) == 0): + return [] + elif(len(candidates) == 1): + return candidates[0] + else: + cost_list = self.get_cost_list(pred_res, pred_res_prob, candidates) + min_address_num = np.min(cost_list) + idxs = np.where(cost_list == min_address_num)[0] + return [candidates[idx] for idx in idxs][0] def abduce(self, data, max_address_num = -1, require_more_address = 0): pred_res, pred_res_prob, ans = data @@ -75,13 +76,16 @@ class AbducerBase(abc.ABC): candidate = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) return candidate - if(self.kb.base != {}): + if self.kb.GKB_flag: all_candidates = self.kb.get_candidates(ans, len(pred_res)) - cost_list = self.hamming_dist(pred_res, all_candidates) - min_address_num = np.min(cost_list) - address_num = min(max_address_num, min_address_num + require_more_address) - idxs = np.where(cost_list <= address_num)[0] - candidates = [all_candidates[idx] for idx in idxs] + if(len(all_candidates) == 0): + return [] + else: + cost_list = self.hamming_dist(pred_res, all_candidates) + min_address_num = np.min(cost_list) + address_num = min(max_address_num, min_address_num + require_more_address) + idxs = np.where(cost_list <= address_num)[0] + candidates = [all_candidates[idx] for idx in idxs] else: candidates, min_address_num, address_num = self.get_abduce_candidates(pred_res, ans, max_address_num, require_more_address) @@ -111,8 +115,7 @@ class AbducerBase(abc.ABC): candidates = [] for address_num in range(len(pred_res) + 1): if(address_num > max_address_num): - print('No candidates found') - return None, None, None + return [], None, None if(address_num == 0): if(abs(self.kb.logic_forward(pred_res) - key) <= 1e-3): @@ -146,24 +149,26 @@ class AbducerBase(abc.ABC): if __name__ == '__main__': - kb = add_KB() + kb = add_KB(GKB_flag = True) abd = AbducerBase(kb, 'hamming') - res = abd.abduce(([1, 1, 1], None, 4), max_address_num = 2, require_more_address = 0) + res = abd.abduce(([1, 1], None, 4), max_address_num = 2, require_more_address = 0) print(res) - res = abd.abduce(([1, 1, 1], None, 4), max_address_num = 2, require_more_address = 1) + res = abd.abduce(([1, 1], None, 4), max_address_num = 2, require_more_address = 1) print(res) - res = abd.abduce(([1, 1, 1], None, 4), max_address_num = 1, require_more_address = 1) + res = abd.abduce(([1, 1], None, 4), max_address_num = 1, require_more_address = 1) print(res) - res = abd.abduce(([1, 1, 1], None, 4), max_address_num = 2, require_more_address = 0) + res = abd.abduce(([1, 1], None, 4), max_address_num = 2, require_more_address = 0) print(res) - res = abd.abduce(([1, 1, 1], None, 5), max_address_num = 2, require_more_address = 1) + res = abd.abduce(([1, 1], None, 5), max_address_num = 2, require_more_address = 1) print(res) print() kb = hwf_KB() - abd = AbducerBase(kb) + abd = AbducerBase(kb, 'hamming') res = abd.abduce((['5', '+', '2'], None, 3), max_address_num = 2, require_more_address = 0) print(res) + res = abd.abduce((['5', '+', '2'], None, 3.09), max_address_num = 2, require_more_address = 0) + print(res) res = abd.abduce((['5', '+', '2'], None, 1.67), max_address_num = 3, require_more_address = 0) print(res) res = abd.abduce((['5', '+', '3'], None, 0.33), max_address_num = 3, require_more_address = 3) From 4a1de111f96d8876f6bd43a69a7658da14cb9221 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 21 Nov 2022 15:00:58 +0800 Subject: [PATCH 054/601] Update kb.py --- abducer/kb.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index c206f62..499d9bb 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -60,7 +60,7 @@ class ClsKB(KBBase): if GKB_flag: X, Y = self.get_GKB(self.pseudo_label_list, self.len_list) for x, y in zip(X, Y): - self.base.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) + self.base.setdefault(len(x), defaultdict(list))[y].append(x) def get_GKB(self, pseudo_label_list, len_list): all_X = [] @@ -104,9 +104,10 @@ class ClsKB(KBBase): class add_KB(ClsKB): - def __init__(self, GKB_flag = False, len_list = [2]): - self.pseudo_label_list = list(range(10)) - super().__init__(GKB_flag, self.pseudo_label_list, len_list) + def __init__(self, GKB_flag = False, \ + pseudo_label_list = list(range(10)), \ + len_list = [2]): + super().__init__(GKB_flag, pseudo_label_list, len_list) def valid_candidate(self, x): return True @@ -116,9 +117,10 @@ class add_KB(ClsKB): class hwf_KB(ClsKB): - def __init__(self, GKB_flag = False, len_list = [1, 3, 5, 7]): - self.pseudo_label_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', '*', '/'] - super().__init__(GKB_flag, self.pseudo_label_list, len_list) + def __init__(self, GKB_flag = False, \ + pseudo_label_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', '*', '/'], \ + len_list = [1, 3, 5, 7]): + super().__init__(GKB_flag, pseudo_label_list, len_list) def valid_candidate(self, formula): if(len(formula) % 2 == 0): From 6c76700be1a4cf98bd32ebad90883da57fcc1b63 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 21 Nov 2022 15:03:10 +0800 Subject: [PATCH 055/601] Update abducer_base.py --- abducer/abducer_base.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 6de9987..a0af59d 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -155,10 +155,6 @@ if __name__ == '__main__': print(res) res = abd.abduce(([1, 1], None, 4), max_address_num = 2, require_more_address = 1) print(res) - res = abd.abduce(([1, 1], None, 4), max_address_num = 1, require_more_address = 1) - print(res) - res = abd.abduce(([1, 1], None, 4), max_address_num = 2, require_more_address = 0) - print(res) res = abd.abduce(([1, 1], None, 5), max_address_num = 2, require_more_address = 1) print(res) print() From 15231012669e0fffe8e684e01aa9bf92d2834e7c Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Mon, 21 Nov 2022 15:23:26 +0800 Subject: [PATCH 056/601] update basic model --- models/basic_model.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/models/basic_model.py b/models/basic_model.py index 86fbea5..182e1e5 100644 --- a/models/basic_model.py +++ b/models/basic_model.py @@ -131,21 +131,19 @@ class BasicModel(): model.train() - loss_value = 0 - for _, data in enumerate(data_loader): - X = data[0].to(device) - Y = data[1].to(device) - pred_Y = model(X) - - loss = criterion(pred_Y, Y) + total_loss, total_num = 0.0, 0 + for data, target in data_loader: + data, target = data.to(device), target.to(device) + out = model(data) + loss = criterion(out, target) optimizer.zero_grad() loss.backward() optimizer.step() - loss_value += loss.item() + total_loss += loss.item() * data.size(0) - return loss_value + return total_loss / total_num def _predict(self, data_loader): model = self.model @@ -155,9 +153,9 @@ class BasicModel(): with torch.no_grad(): results = [] - for _, data in enumerate(data_loader): - X = data[0].to(device) - pred_Y = model(X) + for data, _ in data_loader: + data = data.to(device) + pred_Y = model(data) results.append(pred_Y) return torch.cat(results, axis=0) From 41be49c68ec1c7eb414fc3839815b61305acbaf4 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 21 Nov 2022 15:55:58 +0800 Subject: [PATCH 057/601] Update abducer_base.py --- abducer/abducer_base.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index a0af59d..b26c88a 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -47,15 +47,15 @@ class AbducerBase(abc.ABC): def get_cost_list(self, pred_res, pred_res_prob, candidates): - if(self.dist_func == 'hamming'): + if self.dist_func == 'hamming': return self.hamming_dist(pred_res, candidates) - elif(self.dist_func == 'confidence'): + elif self.dist_func == 'confidence': return self.confidence_dist(pred_res_prob, candidates) def get_min_cost_candidate(self, pred_res, pred_res_prob, candidates): - if(len(candidates) == 0): + if len(candidates) == 0: return [] - elif(len(candidates) == 1): + elif len(candidates) == 1: return candidates[0] else: cost_list = self.get_cost_list(pred_res, pred_res_prob, candidates) @@ -68,9 +68,9 @@ class AbducerBase(abc.ABC): if max_address_num == -1: max_address_num = len(pred_res) - if(self.cache and (tuple(pred_res), ans) in self.cache_min_address_num): + if self.cache and (tuple(pred_res), ans) in self.cache_min_address_num: address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), ans)] + require_more_address) - if((tuple(pred_res), ans, address_num) in self.cache_candidates): + if (tuple(pred_res), ans, address_num) in self.cache_candidates: # print('cached') candidates = self.cache_candidates[(tuple(pred_res), ans, address_num)] candidate = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) @@ -78,7 +78,7 @@ class AbducerBase(abc.ABC): if self.kb.GKB_flag: all_candidates = self.kb.get_candidates(ans, len(pred_res)) - if(len(all_candidates) == 0): + if len(all_candidates) == 0: return [] else: cost_list = self.hamming_dist(pred_res, all_candidates) @@ -90,7 +90,7 @@ class AbducerBase(abc.ABC): else: candidates, min_address_num, address_num = self.get_abduce_candidates(pred_res, ans, max_address_num, require_more_address) - if(self.cache): + if self.cache: self.cache_min_address_num[(tuple(pred_res), ans)] = min_address_num self.cache_candidates[(tuple(pred_res), ans, address_num)] = candidates @@ -104,9 +104,9 @@ class AbducerBase(abc.ABC): for address_idx in address_idx_list: for c in all_address_candidate: pred_res_array = np.array(pred_res) - if(np.count_nonzero(np.array(c) != pred_res_array[np.array(address_idx)]) == address_num): + if np.count_nonzero(np.array(c) != pred_res_array[np.array(address_idx)]) == address_num: pred_res_array[np.array(address_idx)] = c - if(self.kb.logic_forward(pred_res_array) == key): + if self.kb.logic_forward(pred_res_array) == key: new_candidates.append(pred_res_array) return new_candidates, address_num @@ -114,22 +114,22 @@ class AbducerBase(abc.ABC): candidates = [] for address_num in range(len(pred_res) + 1): - if(address_num > max_address_num): + if address_num > max_address_num: return [], None, None - if(address_num == 0): - if(abs(self.kb.logic_forward(pred_res) - key) <= 1e-3): + if address_num == 0: + if abs(self.kb.logic_forward(pred_res) - key) <= 1e-3: candidates.append(pred_res) else: new_candidates, address_num = self.address(address_num, pred_res, key) candidates += new_candidates - if(len(candidates) > 0): + if len(candidates) > 0: min_address_num = address_num break for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): - if(address_num > max_address_num): + if address_num > max_address_num: return candidates, min_address_num, address_num - 1 new_candidates, address_num = self.address(address_num, pred_res, key) candidates += new_candidates From 6925860422ea8f5134c9389dca78af4ad3edaa2a Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 21 Nov 2022 15:56:09 +0800 Subject: [PATCH 058/601] Update kb.py --- abducer/kb.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 499d9bb..7fa4b3f 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -54,10 +54,10 @@ class ClsKB(KBBase): super().__init__() self.GKB_flag = GKB_flag self.pseudo_label_list = pseudo_label_list - self.base = {} self.len_list = len_list if GKB_flag: + self.base = {} X, Y = self.get_GKB(self.pseudo_label_list, self.len_list) for x, y in zip(X, Y): self.base.setdefault(len(x), defaultdict(list))[y].append(x) @@ -82,7 +82,7 @@ class ClsKB(KBBase): pass def get_candidates(self, key, length = None): - if(self.base == {}): + if not self.GKB_flag or self.base == {}: return [] if key is None: @@ -94,13 +94,22 @@ class ClsKB(KBBase): return sum([self.base[l][key] for l in length], []) def get_all_candidates(self): - return sum([sum(v.values(), []) for v in self.base.values()], []) + if not self.GKB_flag or self.base == {}: + return [] + else: + return sum([sum(v.values(), []) for v in self.base.values()], []) def _dict_len(self, dic): - return sum(len(c) for c in dic.values()) + if not self.GKB_flag: + return 0 + else: + return sum(len(c) for c in dic.values()) def __len__(self): - return sum(self._dict_len(v) for v in self.base.values()) + if not self.GKB_flag: + return 0 + else: + return sum(self._dict_len(v) for v in self.base.values()) class add_KB(ClsKB): @@ -123,17 +132,17 @@ class hwf_KB(ClsKB): super().__init__(GKB_flag, pseudo_label_list, len_list) def valid_candidate(self, formula): - if(len(formula) % 2 == 0): + if len(formula) % 2 == 0: return False for i in range(len(formula)): - if(i % 2 == 0 and formula[i] not in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']): + if i % 2 == 0 and formula[i] not in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']: return False - if(i % 2 != 0 and formula[i] not in ['+', '-', '*', '/']): + if i % 2 != 0 and formula[i] not in ['+', '-', '*', '/']: return False return True def logic_forward(self, formula): - if(self.valid_candidate(formula) == False): + if not self.valid_candidate(formula): return np.inf try: return round(eval(''.join(formula)), 2) From 5c6cbd45c74c2099ca5fbc7dc9c88a49bdf19077 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 21 Nov 2022 16:50:11 +0800 Subject: [PATCH 059/601] Update kb.py --- abducer/kb.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 7fa4b3f..8c3f49a 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -127,7 +127,7 @@ class add_KB(ClsKB): class hwf_KB(ClsKB): def __init__(self, GKB_flag = False, \ - pseudo_label_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', '*', '/'], \ + pseudo_label_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', 'times', 'div'], \ len_list = [1, 3, 5, 7]): super().__init__(GKB_flag, pseudo_label_list, len_list) @@ -137,7 +137,7 @@ class hwf_KB(ClsKB): for i in range(len(formula)): if i % 2 == 0 and formula[i] not in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']: return False - if i % 2 != 0 and formula[i] not in ['+', '-', '*', '/']: + if i % 2 != 0 and formula[i] not in ['+', '-', 'times', 'div']: return False return True @@ -145,6 +145,8 @@ class hwf_KB(ClsKB): if not self.valid_candidate(formula): return np.inf try: + mapping = {'0':'0', '1':'1', '2':'2', '3':'3', '4':'4', '5':'5', '6':'6', '7':'7', '8':'8', '9':'9', '+':'+', '-':'-', 'times':'*', 'div':'/'} + formula = [mapping[f] for f in formula] return round(eval(''.join(formula)), 2) except ZeroDivisionError: return np.inf From 06830d5a10713ff78ff7763bbfb417e62acc7a32 Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Mon, 21 Nov 2022 17:01:03 +0800 Subject: [PATCH 060/601] update basic_model.py --- models/basic_model.py | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/models/basic_model.py b/models/basic_model.py index 86fbea5..669474f 100644 --- a/models/basic_model.py +++ b/models/basic_model.py @@ -20,13 +20,12 @@ import os from multiprocessing import Pool class XYDataset(Dataset): - def __init__(self, X, Y, transform=None, target_transform=None): + def __init__(self, X, Y, transform=None): self.X = X - self.Y = Y + self.Y = torch.LongTensor(Y) self.n_sample = len(X) self.transform = transform - self.target_transform = target_transform def __len__(self): return len(self.X) @@ -39,8 +38,6 @@ class XYDataset(Dataset): img = self.transform(img) label = self.Y[index] - if self.target_transform is not None: - label = self.target_transform(label) return (img, label) @@ -64,7 +61,6 @@ class BasicModel(): save_interval = None, save_dir = None, transform = None, - target_transform = None, collate_fn = None, recorder = None): @@ -78,7 +74,6 @@ class BasicModel(): self.criterion = criterion self.optimizer = optimizer self.transform = transform - self.target_transform = target_transform self.device = device if recorder is None: @@ -114,9 +109,8 @@ class BasicModel(): if data_loader is None: collate_fn = self.collate_fn transform = self.transform - target_transform = self.target_transform - train_dataset = XYDataset(X, y, transform=transform, target_transform=target_transform) + train_dataset = XYDataset(X, y, transform=transform) sampler = None data_loader = torch.utils.data.DataLoader(train_dataset, batch_size=self.batch_size, \ shuffle=True, sampler=sampler, num_workers=int(self.num_workers), \ @@ -166,10 +160,9 @@ class BasicModel(): if data_loader is None: collate_fn = self.collate_fn transform = self.transform - target_transform = self.target_transform Y = [0] * len(X) - val_dataset = XYDataset(X, Y, transform=transform, target_transform=target_transform) + val_dataset = XYDataset(X, Y, transform=transform) sampler = None data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=self.batch_size, \ shuffle=False, sampler=sampler, num_workers=int(self.num_workers), \ @@ -184,10 +177,9 @@ class BasicModel(): if data_loader is None: collate_fn = self.collate_fn transform = self.transform - target_transform = self.target_transform Y = [0] * len(X) - val_dataset = XYDataset(X, Y, transform=transform, target_transform=target_transform) + val_dataset = XYDataset(X, Y, transform=transform) sampler = None data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=self.batch_size, \ shuffle=False, sampler=sampler, num_workers=int(self.num_workers), \ @@ -231,9 +223,8 @@ class BasicModel(): if data_loader is None: collate_fn = self.collate_fn transform = self.transform - target_transform = self.target_transform - val_dataset = XYDataset(X, y, transform=transform, target_transform=target_transform) + val_dataset = XYDataset(X, y, transform=transform) sampler = None data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=self.batch_size, \ shuffle=True, sampler=sampler, num_workers=int(self.num_workers), \ From 5d47158adb0d8e5269113313be54fef84edf19d0 Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Mon, 21 Nov 2022 17:02:46 +0800 Subject: [PATCH 061/601] update example.py and polg.py, add .gitignore --- .gitignore | 3 +++ example.py | 34 ++++++---------------------------- utils/plog.py | 40 ++++++++++++++++------------------------ 3 files changed, 25 insertions(+), 52 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8ebaf8d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.pyc +/results +raw/ \ No newline at end of file diff --git a/example.py b/example.py index 1a20b28..d63185c 100644 --- a/example.py +++ b/example.py @@ -11,16 +11,13 @@ #================================================================# from utils.plog import logger -import numpy as np -import time import framework -import utils.plog as plog import torch.nn as nn import torch from models.lenet5 import LeNet5 from models.basic_model import BasicModel -from models.wabl_models import MyModel +from models.wabl_models import WABLBasicModel from multiprocessing import Pool import os @@ -29,51 +26,32 @@ from abducer.kb import add_KB, hwf_KB from datasets.mnist_add.get_mnist_add import get_mnist_add from datasets.hwf.get_hwf import get_hwf -class Params: - imgH = 28 - imgW = 28 - keep_ratio = True - saveInterval = 10 - batchSize = 16 - workers = 16 - n_epoch = 1 - stop_loss = None - def run_test(): - - result_dir = 'results' - - recorder_file_path = f"{result_dir}/1116.pk"# kb = add_KB() # kb = hwf_KB() - abducer = AbducerBase(kb, 2) + abducer = AbducerBase(kb) recorder = logger() - recorder.set_savefile("test.log") train_X, train_Z, train_Y = get_mnist_add(train = True, get_pseudo_label = True) test_X, test_Z, test_Y = get_mnist_add(train = False, get_pseudo_label = True) - recorder = plog.ResultRecorder() cls = LeNet5(num_classes=len(kb.pseudo_label_list), image_size=(train_X[0][0].shape[1:])) - criterion = nn.CrossEntropyLoss(size_average=True) + criterion = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(cls.parameters(), lr=0.001, betas=(0.9, 0.99)) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - base_model = BasicModel(cls, criterion, optimizer, device, Params(), recorder=recorder) - model = MyModel(base_model, kb.pseudo_label_list) + base_model = BasicModel(cls, criterion, optimizer, device, recorder=recorder) + model = WABLBasicModel(base_model, kb.pseudo_label_list) res = framework.train(model, abducer, train_X, train_Z, train_Y, sample_num = 10000, verbose = 1) print(res) - - recorder.dump(open(recorder_file_path, "wb")) + recorder.dump() return True if __name__ == "__main__": - os.system("mkdir results") - run_test() diff --git a/utils/plog.py b/utils/plog.py index 941dc11..4aee019 100644 --- a/utils/plog.py +++ b/utils/plog.py @@ -16,51 +16,42 @@ import pickle as pk import os import functools -log_name = "default_log.txt" -logging.basicConfig(level=logging.INFO, - filename=log_name, - filemode='a', - format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') - global recorder recorder = None -def mkdir(dirpath): - if not os.path.exists(dirpath): - os.makedirs(dirpath) - class ResultRecorder: - def __init__(self, pk_dir = None, pk_filepath = None): - self.set_savefile(pk_dir, pk_filepath) - + def __init__(self, pk_dir = 'results', pk_filepath = None): self.result = {} + + logging.basicConfig(level=logging.DEBUG, filemode='a') + + self.set_savefile(pk_dir, pk_filepath) + logging.info("===========================================================") - logging.info("============= Result Recorder Version: 0.02 ===============") + logging.info("============= Result Recorder Version: 0.03 ===============") logging.info("===========================================================\n") pass def set_savefile(self, pk_dir = None, pk_filepath = None): if pk_dir is None: - pk_dir = "result" - mkdir(pk_dir) + pk_dir = "results" + + if not os.path.exists(pk_dir): + os.makedirs(pk_dir) if pk_filepath is None: local_time = time.strftime("%Y%m%d_%H_%M_%S", time.localtime()) pk_filepath = os.path.join(pk_dir, local_time + ".pk") - - self.save_file = open(pk_filepath, "wb") - logger = logging.getLogger() - logger.handlers[0].stream.close() - logger.removeHandler(logger.handlers[0]) + self.save_file = pk_filepath filename = os.path.join(pk_dir, local_time + ".txt") file_handler = logging.FileHandler(filename) file_handler.setLevel(logging.DEBUG) formatter = logging.Formatter('%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') file_handler.setFormatter(formatter) - logger.addHandler(file_handler) + logging.getLogger().addHandler(file_handler) def print(self, *argv, screen = False): info = "" @@ -99,7 +90,8 @@ class ResultRecorder: def dump(self, save_file = None): if save_file is None: save_file = self.save_file - pk.dump(self.result, save_file) + with open(save_file, 'wb') as f: + pk.dump(self.result, f) def clock(self, func): @functools.wraps(func) @@ -111,7 +103,7 @@ class ResultRecorder: name = func.__name__ # arg_str = ','.join(repr(arg) for arg in args) # context = f"{name}: ({arg_str})=>({result}), cost {elapsed}s" - context = f"{name}: ()=>(), cost {elapsed}s" + context = f"{name}: cost {elapsed}s" self.write_kv("func:", context) return result From c681e3cb0a521d10cec905dee8ad78ca1dd88939 Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Mon, 21 Nov 2022 22:42:07 +0800 Subject: [PATCH 062/601] update basic_model.py and related part in other files --- abducer/abducer_base.py | 3 +- example.py | 4 +- framework.py | 10 ++- models/basic_model.py | 135 ++++++++++++++++++---------------------- utils/plog.py | 36 +++++------ 5 files changed, 84 insertions(+), 104 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index b26c88a..54380ec 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -11,8 +11,7 @@ #================================================================# import abc -from kb import add_KB, hwf_KB -# from abducer.kb import add_KB, hwf_KB +from abducer.kb import add_KB, hwf_KB import numpy as np from itertools import product, combinations diff --git a/example.py b/example.py index d63185c..dad33f7 100644 --- a/example.py +++ b/example.py @@ -43,11 +43,11 @@ def run_test(): optimizer = torch.optim.Adam(cls.parameters(), lr=0.001, betas=(0.9, 0.99)) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - base_model = BasicModel(cls, criterion, optimizer, device, recorder=recorder) + base_model = BasicModel(cls, criterion, optimizer, device, save_interval=1, save_dir=recorder.save_dir, num_epochs=1, recorder=recorder) model = WABLBasicModel(base_model, kb.pseudo_label_list) res = framework.train(model, abducer, train_X, train_Z, train_Y, sample_num = 10000, verbose = 1) - print(res) + recorder.print("abl_acc is ", res) recorder.dump() return True diff --git a/framework.py b/framework.py index a37483b..4f84694 100644 --- a/framework.py +++ b/framework.py @@ -123,7 +123,7 @@ def is_all_sublabel_exist(labels, std_label_list): def pretrain(model, X, Z): pass -def train(model, abducer, X, Z, Y, epochs = 10, sample_num = -1, verbose = -1): +def train(model, abducer, X, Z, Y, epochs = 5, sample_num = -1, verbose = -1): # Set default parameters if sample_num == -1: sample_num = len(X) @@ -138,10 +138,7 @@ def train(model, abducer, X, Z, Y, epochs = 10, sample_num = -1, verbose = -1): predict_func = clocker(model.predict) train_func = clocker(model.train) - abduce_func = clocker(abducer.batch_abduce) - - epochs = 50 # Abductive learning train process for epoch_idx in range(epochs): @@ -153,12 +150,13 @@ def train(model, abducer, X, Z, Y, epochs = 10, sample_num = -1, verbose = -1): if(char_acc_flag): ori_char_acc = get_char_acc(Z, preds_res['cls']) abd_char_acc = get_char_acc(abduced_Z, preds_res['cls']) - print('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc, ' ori_char_acc:', ori_char_acc, ' abd_char_acc:', abd_char_acc) + INFO('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc, ' ori_char_acc:', ori_char_acc, ' abd_char_acc:', abd_char_acc) else: - print('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc) + INFO('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc) finetune_X, finetune_Z = filter_data(X, abduced_Z) if len(finetune_X) > 0: + # model.valid(finetune_X, finetune_Z) train_func(finetune_X, finetune_Z) else: INFO("lack of data, all abduced failed", len(finetune_X)) diff --git a/models/basic_model.py b/models/basic_model.py index 00efd30..11063a8 100644 --- a/models/basic_model.py +++ b/models/basic_model.py @@ -55,7 +55,7 @@ class BasicModel(): optimizer, device, batch_size = 1, - num_epochs = 10, + num_epochs = 1, stop_loss = 0.01, num_workers = 0, save_interval = None, @@ -89,15 +89,15 @@ class BasicModel(): recorder = self.recorder recorder.print("model fitting") - min_loss = 999999999 + min_loss = 1e10 for epoch in range(n_epoch): loss_value = self.train_epoch(data_loader) recorder.print(f"{epoch}/{n_epoch} model training loss is {loss_value}") - if loss_value < min_loss: + if min_loss < 0 or loss_value < min_loss: min_loss = loss_value - if epoch > 0 and self.save_interval is not None and epoch % self.save_interval == 0: + if self.save_interval is not None and (epoch + 1) % self.save_interval == 0: assert self.save_dir is not None - self.save(self.save_dir) + self.save(epoch + 1, self.save_dir) if stop_loss is not None and loss_value < stop_loss: break recorder.print("Model fitted, minimal loss is ", min_loss) @@ -107,14 +107,7 @@ class BasicModel(): X = None, y = None): if data_loader is None: - collate_fn = self.collate_fn - transform = self.transform - - train_dataset = XYDataset(X, y, transform=transform) - sampler = None - data_loader = torch.utils.data.DataLoader(train_dataset, batch_size=self.batch_size, \ - shuffle=True, sampler=sampler, num_workers=int(self.num_workers), \ - collate_fn=collate_fn) + data_loader = self._data_loader(X, y) return self._fit(data_loader, self.num_epochs, self.stop_loss) def train_epoch(self, data_loader): @@ -136,6 +129,7 @@ class BasicModel(): optimizer.step() total_loss += loss.item() * data.size(0) + total_num += data.size(0) return total_loss / total_num @@ -149,107 +143,98 @@ class BasicModel(): results = [] for data, _ in data_loader: data = data.to(device) - pred_Y = model(data) - results.append(pred_Y) + out = model(data) + results.append(out) return torch.cat(results, axis=0) def predict(self, data_loader = None, X = None, print_prefix = ""): - if data_loader is None: - collate_fn = self.collate_fn - transform = self.transform - - Y = [0] * len(X) - val_dataset = XYDataset(X, Y, transform=transform) - sampler = None - data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=self.batch_size, \ - shuffle=False, sampler=sampler, num_workers=int(self.num_workers), \ - collate_fn=collate_fn) - recorder = self.recorder - recorder.print('Start Predict ', print_prefix) - Y = self._predict(data_loader).argmax(axis=1) - return [int(y) for y in Y] + recorder.print('Start Predict Class ', print_prefix) - def predict_proba(self, data_loader = None, X = None, print_prefix = ""): if data_loader is None: - collate_fn = self.collate_fn - transform = self.transform - - Y = [0] * len(X) - val_dataset = XYDataset(X, Y, transform=transform) - sampler = None - data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=self.batch_size, \ - shuffle=False, sampler=sampler, num_workers=int(self.num_workers), \ - collate_fn=collate_fn) + data_loader = self._data_loader(X) + return self._predict(data_loader).argmax(axis=1).cpu().numpy() + def predict_proba(self, data_loader = None, X = None, print_prefix = ""): recorder = self.recorder - recorder.print('Start Predict ', print_prefix) - return torch.softmax(self._predict(data_loader), axis=1).cpu().numpy() + recorder.print('Start Predict Probability ', print_prefix) - def _val(self, data_loader, print_prefix): + if data_loader is None: + data_loader = self._data_loader(X) + return self._predict(data_loader).softmax(axis=1).cpu().numpy() + + def _val(self, data_loader): model = self.model criterion = self.criterion - recorder = self.recorder device = self.device - recorder.print('Start val ', print_prefix) model.eval() - - n_correct = 0 - pred_num = 0 - loss_value = 0 + + total_correct_num, total_num, total_loss = 0, 0, 0.0 + with torch.no_grad(): - for _, data in enumerate(data_loader): - X = data[0].to(device) - Y = data[1].to(device) + for data, target in data_loader: + data, target = data.to(device), target.to(device) - pred_Y = model(X) + out = model(data) - correct_num = sum(Y == pred_Y.argmax(axis=1)) - loss = criterion(pred_Y, Y) - loss_value += loss.item() + correct_num = sum(target == out.argmax(axis=1)).item() + loss = criterion(out, target) + total_loss += loss.item() * data.size(0) - n_correct += correct_num - pred_num += len(X) + total_correct_num += correct_num + total_num += data.size(0) + + mean_loss = total_loss / total_num + accuracy = total_correct_num / total_num - accuracy = float(n_correct) / float(pred_num) - recorder.print('[%s] Val loss: %f, accuray: %f' % (print_prefix, loss_value, accuracy)) - return accuracy + return mean_loss, accuracy def val(self, data_loader = None, X = None, y = None, print_prefix = ""): - if data_loader is None: - collate_fn = self.collate_fn - transform = self.transform + recorder = self.recorder + recorder.print('Start val ', print_prefix) - val_dataset = XYDataset(X, y, transform=transform) - sampler = None - data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=self.batch_size, \ - shuffle=True, sampler=sampler, num_workers=int(self.num_workers), \ - collate_fn=collate_fn) - return self._val(data_loader, print_prefix) + if data_loader is None: + data_loader = self._data_loader(X, y) + mean_loss, accuracy = self._val(data_loader) + recorder.print('[%s] Val loss: %f, accuray: %f' % (print_prefix, mean_loss, accuracy)) + return accuracy def score(self, data_loader = None, X = None, y = None, print_prefix = ""): return self.val(data_loader, X, y, print_prefix) - def save(self, save_dir): + def _data_loader(self, X, y = None): + collate_fn = self.collate_fn + transform = self.transform + + if y is None: + y = [0] * len(X) + dataset = XYDataset(X, y, transform=transform) + sampler = None + data_loader = torch.utils.data.DataLoader(dataset, batch_size=self.batch_size, \ + shuffle=False, sampler=sampler, num_workers=int(self.num_workers), \ + collate_fn=collate_fn) + return data_loader + + def save(self, epoch_id, save_dir): recorder = self.recorder if not os.path.exists(save_dir): os.mkdir(save_dir) recorder.print("Saving model and opter") - save_path = os.path.join(save_dir, "net.pth") + save_path = os.path.join(save_dir, str(epoch_id) + "_net.pth") torch.save(self.model.state_dict(), save_path) - save_path = os.path.join(save_dir, "opt.pth") + save_path = os.path.join(save_dir, str(epoch_id) + "_opt.pth") torch.save(self.optimizer.state_dict(), save_path) - def load(self, load_dir): + def load(self, epoch_id, load_dir): recorder = self.recorder recorder.print("Loading model and opter") - load_path = os.path.join(load_dir, "net.pth") + load_path = os.path.join(load_dir, str(epoch_id) + "_net.pth") self.model.load_state_dict(torch.load(load_path)) - load_path = os.path.join(load_dir, "opt.pth") + load_path = os.path.join(load_dir, str(epoch_id) + "_opt.pth") self.optimizer.load_state_dict(torch.load(load_path)) if __name__ == "__main__": diff --git a/utils/plog.py b/utils/plog.py index 4aee019..178b8b7 100644 --- a/utils/plog.py +++ b/utils/plog.py @@ -20,12 +20,11 @@ global recorder recorder = None class ResultRecorder: - def __init__(self, pk_dir = 'results', pk_filepath = None): - self.result = {} - + def __init__(self): logging.basicConfig(level=logging.DEBUG, filemode='a') - self.set_savefile(pk_dir, pk_filepath) + self.result = {} + self.set_savefile() logging.info("===========================================================") logging.info("============= Result Recorder Version: 0.03 ===============") @@ -33,20 +32,19 @@ class ResultRecorder: pass - def set_savefile(self, pk_dir = None, pk_filepath = None): - if pk_dir is None: - pk_dir = "results" - - if not os.path.exists(pk_dir): - os.makedirs(pk_dir) + def set_savefile(self): + local_time = time.strftime("%Y%m%d_%H_%M_%S", time.localtime()) - if pk_filepath is None: - local_time = time.strftime("%Y%m%d_%H_%M_%S", time.localtime()) - pk_filepath = os.path.join(pk_dir, local_time + ".pk") + save_dir = os.path.join("results", local_time) + save_file_path = os.path.join(save_dir, "result.pk") - self.save_file = pk_filepath + self.save_dir = save_dir + self.save_file_path = save_file_path + + if not os.path.exists(save_dir): + os.makedirs(save_dir) - filename = os.path.join(pk_dir, local_time + ".txt") + filename = os.path.join(save_dir, "log.txt") file_handler = logging.FileHandler(filename) file_handler.setLevel(logging.DEBUG) formatter = logging.Formatter('%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') @@ -87,10 +85,10 @@ class ResultRecorder: #self.print_result(label + ":" + str(data)) self.store_kv(label, data) - def dump(self, save_file = None): - if save_file is None: - save_file = self.save_file - with open(save_file, 'wb') as f: + def dump(self, save_file_path = None): + if save_file_path is None: + save_file_path = self.save_file_path + with open(save_file_path, 'wb') as f: pk.dump(self.result, f) def clock(self, func): From f9ea562a3f86fa39493f4be31c50debdac7e8c21 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 22 Nov 2022 10:26:39 +0800 Subject: [PATCH 063/601] Update abducer_base.py --- abducer/abducer_base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 54380ec..284ebe4 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -11,6 +11,7 @@ #================================================================# import abc +# from kb import add_KB, hwf_KB from abducer.kb import add_KB, hwf_KB import numpy as np From 778ae172dfe1972a8d5fa75e149aff0ea2d530e0 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 22 Nov 2022 10:27:15 +0800 Subject: [PATCH 064/601] Update get_mnist_add.py --- datasets/mnist_add/get_mnist_add.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/datasets/mnist_add/get_mnist_add.py b/datasets/mnist_add/get_mnist_add.py index 1af834a..871e503 100644 --- a/datasets/mnist_add/get_mnist_add.py +++ b/datasets/mnist_add/get_mnist_add.py @@ -23,9 +23,9 @@ def get_data(file, img_dataset, get_pseudo_label): def get_mnist_add(train = True, get_pseudo_label = False): transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081, ))]) - img_dataset = torchvision.datasets.MNIST(root='./datasets/mnist_add/', train=True, download=True, transform=transform) + img_dataset = torchvision.datasets.MNIST(root='./datasets/mnist_add/', train=train, download=True, transform=transform) - if(train): + if train: file = './datasets/mnist_add/train_data.txt' else: file = './datasets/mnist_add/test_data.txt' From af00136661a327c031af7080e23615dceaa533a1 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 22 Nov 2022 10:27:49 +0800 Subject: [PATCH 065/601] Update get_hwf.py --- datasets/hwf/get_hwf.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/datasets/hwf/get_hwf.py b/datasets/hwf/get_hwf.py index f94f1a5..543e0d5 100644 --- a/datasets/hwf/get_hwf.py +++ b/datasets/hwf/get_hwf.py @@ -24,11 +24,10 @@ def get_data(file, get_pseudo_label, precision_num = 2): imgs.append(img) if(get_pseudo_label): imgs_pseudo_label.append(img_path.split('/')[0]) - if(len(imgs) == 3): - X.append(imgs) - if(get_pseudo_label): - Z.append(imgs_pseudo_label) - Y.append(round(data[idx]['res'], precision_num)) + X.append(imgs) + if(get_pseudo_label): + Z.append(imgs_pseudo_label) + Y.append(round(data[idx]['res'], precision_num)) if(get_pseudo_label): return X, Z, Y From 740df944c1c09aca25aa50997c453601e6e63070 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 22 Nov 2022 10:28:30 +0800 Subject: [PATCH 066/601] Update get_hwf.py --- datasets/hwf/get_hwf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/datasets/hwf/get_hwf.py b/datasets/hwf/get_hwf.py index 543e0d5..084ed16 100644 --- a/datasets/hwf/get_hwf.py +++ b/datasets/hwf/get_hwf.py @@ -22,14 +22,14 @@ def get_data(file, get_pseudo_label, precision_num = 2): img = Image.open(img_dir + img_path).convert('L') img = img_transform(img) imgs.append(img) - if(get_pseudo_label): + if get_pseudo_label: imgs_pseudo_label.append(img_path.split('/')[0]) X.append(imgs) - if(get_pseudo_label): + if get_pseudo_label: Z.append(imgs_pseudo_label) Y.append(round(data[idx]['res'], precision_num)) - if(get_pseudo_label): + if get_pseudo_label: return X, Z, Y else: return X, None, Y From 1258d83edc3538376474b31781284cf585ee3c14 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 22 Nov 2022 10:29:05 +0800 Subject: [PATCH 067/601] Update get_hwf.py --- datasets/hwf/get_hwf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datasets/hwf/get_hwf.py b/datasets/hwf/get_hwf.py index 084ed16..b478a15 100644 --- a/datasets/hwf/get_hwf.py +++ b/datasets/hwf/get_hwf.py @@ -9,7 +9,7 @@ img_transform = transforms.Compose([ def get_data(file, get_pseudo_label, precision_num = 2): X = [] - if(get_pseudo_label): + if get_pseudo_label: Z = [] Y = [] img_dir = './datasets/hwf/data/Handwritten_Math_Symbols/' From 44b140c1fd7c5d158c0d818f5943083c688369e9 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 22 Nov 2022 10:29:29 +0800 Subject: [PATCH 068/601] Update get_mnist_add.py --- datasets/mnist_add/get_mnist_add.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/datasets/mnist_add/get_mnist_add.py b/datasets/mnist_add/get_mnist_add.py index 871e503..d00c6ce 100644 --- a/datasets/mnist_add/get_mnist_add.py +++ b/datasets/mnist_add/get_mnist_add.py @@ -5,18 +5,18 @@ from torchvision.transforms import transforms def get_data(file, img_dataset, get_pseudo_label): X = [] - if(get_pseudo_label): + if get_pseudo_label: Z = [] Y = [] with open(file) as f: for line in f: line = line.strip().split(' ') X.append([img_dataset[int(line[0])][0], img_dataset[int(line[1])][0]]) - if(get_pseudo_label): + if get_pseudo_label: Z.append([img_dataset[int(line[0])][1], img_dataset[int(line[1])][1]]) Y.append(int(line[2])) - if(get_pseudo_label): + if get_pseudo_label: return X, Z, Y else: return X, None, Y From ef0298e91a44c1a9502eb50407b2c9d8987f805f Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 22 Nov 2022 12:34:37 +0800 Subject: [PATCH 069/601] Update kb.py --- abducer/kb.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 8c3f49a..e987d15 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -34,10 +34,6 @@ class KBBase(ABC): def logic_forward(self): pass - @abstractmethod - def valid_candidate(self): - pass - def _length(self, length): if length is None: length = list(self.base.keys()) @@ -57,6 +53,7 @@ class ClsKB(KBBase): self.len_list = len_list if GKB_flag: + # self.base = np.load('abducer/hwf.npy', allow_pickle=True).item() self.base = {} X, Y = self.get_GKB(self.pseudo_label_list, self.len_list) for x, y in zip(X, Y): @@ -70,14 +67,12 @@ class ClsKB(KBBase): X = [] Y = [] for x in all_X: - if self.valid_candidate(x): + y = self.logic_forward(x) + if y != np.inf: X.append(x) - Y.append(self.logic_forward(x)) + Y.append(y) return X, Y - def valid_candidate(self): - pass - def logic_forward(self): pass @@ -88,7 +83,7 @@ class ClsKB(KBBase): if key is None: return self.get_all_candidates() - if (type(length) is int and length not in self.len_list): + if type(length) is int and length not in self.len_list: return [] length = self._length(length) return sum([self.base[l][key] for l in length], []) @@ -117,9 +112,6 @@ class add_KB(ClsKB): pseudo_label_list = list(range(10)), \ len_list = [2]): super().__init__(GKB_flag, pseudo_label_list, len_list) - - def valid_candidate(self, x): - return True def logic_forward(self, nums): return sum(nums) From f78c69ae105bf92fda477c13b88de5e76249f0d0 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 22 Nov 2022 13:48:50 +0800 Subject: [PATCH 070/601] Create lenet5.py --- models/lenet5.py | 60 ++++++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 38 deletions(-) diff --git a/models/lenet5.py b/models/lenet5.py index 56c1ca6..1016d2c 100644 --- a/models/lenet5.py +++ b/models/lenet5.py @@ -52,48 +52,32 @@ class LeNet5(nn.Module): return x def num_flat_features(self, x): - #x.size()返回值为(256, 16, 5, 5),size的值为(16, 5, 5),256是batch_size - size = x.size()[1:] #x.size返回的是一个元组,size表示截å–元组中第二个开始的数字 + size = x.size()[1:] num_features = 1 for s in size: num_features *= s return num_features -class Params: - imgH = 28 - imgW = 28 - keep_ratio = True - saveInterval = 10 - batchSize = 16 - num_workers = 16 -def get_data(): #æ•°æ®é¢„å¤„ç† - transform = transforms.Compose([transforms.ToTensor(), - transforms.Normalize((0.5), (0.5))]) - #transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]) - #训练集 - train_set = torchvision.datasets.MNIST(root='data/', train=True, transform=transform, download=True) - train_loader = torch.utils.data.DataLoader(train_set, batch_size=1024, shuffle=True, num_workers = 16) - #测试集 - test_set = torchvision.datasets.MNIST(root='data/', train=False, transform=transform, download=True) - test_loader = torch.utils.data.DataLoader(test_set, batch_size = 1024, shuffle = False, num_workers = 16) - classes = ('plane','car','bird','cat','deer','dog','frog','horse','ship','truck') - - return train_loader, test_loader, classes - -if __name__ == "__main__": - recorder = plog.ResultRecorder() - cls = LeNet5() - criterion = nn.CrossEntropyLoss(size_average=True) - optimizer = torch.optim.Adam(cls.parameters(), lr=0.001, betas=(0.9, 0.99)) - device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - model = BasicModel(cls, criterion, optimizer, None, device, Params(), recorder) - - train_loader, test_loader, classes = get_data() - - #model.val(test_loader, print_prefix = "before training") - model.fit(train_loader, n_epoch = 100) - model.val(test_loader, print_prefix = "after trained") - res = model.predict(test_loader, print_prefix = "predict") - print(res.argmax(axis=1)[:10]) +class SymbolNet(nn.Module): + def __init__(self, num_classes=14): + super(SymbolNet, self).__init__() + self.conv1 = nn.Conv2d(1, 32, 3, stride = 1, padding = 1) + self.conv2 = nn.Conv2d(32, 64, 3, stride = 1, padding = 1) + self.dropout1 = nn.Dropout2d(0.25) + self.dropout2 = nn.Dropout2d(0.5) + self.fc1 = nn.Linear(30976, 128) + self.fc2 = nn.Linear(128, num_classes) + def forward(self, x): + x = self.conv1(x) + x = F.relu(x) + x = self.conv2(x) + x = F.max_pool2d(x, 2) + x = self.dropout1(x) + x = torch.flatten(x, 1) + x = self.fc1(x) + x = F.relu(x) + x = self.dropout2(x) + x = self.fc2(x) + return x From d9313561724357ff0596aafd78fbab85891101ec Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Tue, 22 Nov 2022 15:50:37 +0800 Subject: [PATCH 071/601] fix bug in plog.py --- utils/plog.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/utils/plog.py b/utils/plog.py index 178b8b7..9a3ab05 100644 --- a/utils/plog.py +++ b/utils/plog.py @@ -37,9 +37,10 @@ class ResultRecorder: save_dir = os.path.join("results", local_time) save_file_path = os.path.join(save_dir, "result.pk") + save_file = open(save_file_path, "wb") self.save_dir = save_dir - self.save_file_path = save_file_path + self.save_file = save_file if not os.path.exists(save_dir): os.makedirs(save_dir) @@ -85,11 +86,10 @@ class ResultRecorder: #self.print_result(label + ":" + str(data)) self.store_kv(label, data) - def dump(self, save_file_path = None): - if save_file_path is None: - save_file_path = self.save_file_path - with open(save_file_path, 'wb') as f: - pk.dump(self.result, f) + def dump(self, save_file = None): + if save_file is None: + save_file = self.save_file + pk.dump(self.result, save_file) def clock(self, func): @functools.wraps(func) From 6806a3cfbf76dab3d556204be8b93a4f1f69ed8e Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Tue, 22 Nov 2022 16:11:08 +0800 Subject: [PATCH 072/601] fix bug in plog.py --- utils/plog.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/utils/plog.py b/utils/plog.py index 9a3ab05..0b8f5b5 100644 --- a/utils/plog.py +++ b/utils/plog.py @@ -36,15 +36,14 @@ class ResultRecorder: local_time = time.strftime("%Y%m%d_%H_%M_%S", time.localtime()) save_dir = os.path.join("results", local_time) + if not os.path.exists(save_dir): + os.makedirs(save_dir) save_file_path = os.path.join(save_dir, "result.pk") save_file = open(save_file_path, "wb") self.save_dir = save_dir self.save_file = save_file - if not os.path.exists(save_dir): - os.makedirs(save_dir) - filename = os.path.join(save_dir, "log.txt") file_handler = logging.FileHandler(filename) file_handler.setLevel(logging.DEBUG) From 4677d2651f9b0c589a42b7caa34b3ce19fb84185 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 22 Nov 2022 18:50:22 +0800 Subject: [PATCH 073/601] Update framework.py --- framework.py | 129 ++++++--------------------------------------------- 1 file changed, 14 insertions(+), 115 deletions(-) diff --git a/framework.py b/framework.py index 4f84694..7f0debf 100644 --- a/framework.py +++ b/framework.py @@ -16,7 +16,6 @@ import numpy as np from utils.plog import INFO, DEBUG, clocker -@clocker def block_sample(X, Z, Y, sample_num, epoch_idx): part_num = (len(X) // sample_num) if part_num == 0: @@ -34,96 +33,40 @@ def get_taglist(self, Z): tmp = sorted(list(set(tmp))) return tmp -def get_abl_acc(Y, pseudo_Z, logic_forward): +def get_abl_acc(pred_Z, Y, logic_forward): abl_acc = 0 - for y, pseudo_z in zip(Y, pseudo_Z): - if(logic_forward(pseudo_z) == y): + for pred_z, y in zip(pred_Z, Y): + if(logic_forward(pred_z) == y): abl_acc += 1 return abl_acc / len(Y) -def get_char_acc(Z, pseudo_Z): +def get_char_acc(Z, pred_Z): char_acc = 0 char_num = 0 - for z, pseudo_z in zip(Z, pseudo_Z): + for pred_z, z in zip(pred_Z, Z): char_num += len(z) for zidx in range(len(z)): - if(z[zidx] == pseudo_z[zidx]): + if(pred_z[zidx] == z[zidx]): char_acc += 1 return char_acc / char_num - -# def result_statistics(pseudo_Y, Y, abduced_Y): - -# abd_err_num = 0 -# abd_char_num = 0 -# abd_char_acc = 0 -# abd_failed = 0 -# word_err_num = 0 - -# ori_char_num = 0 -# ori_char_acc = 0 - -# for tidx, (pseudo_y, y, abduced_y) in enumerate(zip(pseudo_Y, Y, abduced_Y)): -# pseudo_y = pseudo_y -# if sum(abduced_y != y) != 0: -# abd_err_num += 1 -# if abduced_y is not None: -# abd_char_num += len(y) -# abd_char_acc += sum(abduced_y == y) -# else: -# abd_failed += 1 - -# ori_char_num += len(pseudo_y) -# ori_char_acc += sum(pseudo_y == y) - -# if abduced_y is not None and sum(y != pseudo_y) == 0 and sum(pseudo_y != abduced_y) > 0: -# INFO(pseudo_y, y, abduced_y) -# pk.dump((pseudo_y, y, abduced_y), open("bug.pk", "wb")) -# if sum(pseudo_y != y) != 0: -# word_err_num += 1 - -# INFO("") -# INFO("Abd word level accuracy:", 1 - word_err_num / len(pseudo_Y)) -# INFO("Abd char level accuracy:", abd_char_acc / abd_char_num) -# INFO("Ori char level accuracy:", ori_char_acc / ori_char_num) -# INFO("") - -# result = {"total_word" : len(pseudo_Y), "accuracy_word" : len(pseudo_Y) - word_err_num, -# "total_abd_char": abd_char_num, "accuracy_abd_char" : abd_char_acc, -# "total_ori_char": ori_char_num, "accuracy_ori_char" : ori_char_acc, -# "total_abd_failed": abd_failed} - -# return result - -@clocker def filter_data(X, abduced_Z): finetune_Z = [] finetune_X = [] for abduced_x, abduced_z in zip(X, abduced_Z): - if abduced_z is not None: + if abduced_z is not []: finetune_X.append(abduced_x) finetune_Z.append(abduced_z) return finetune_X, finetune_Z -@clocker -def is_all_sublabel_exist(labels, std_label_list): - if not labels: - return False - - labels = np.array(labels).T - for idx, (std_label, label) in enumerate(zip(std_label_list, labels)): - std_num = len(set(std_label)) - sublabel_num = len(set(label)) - if std_num != sublabel_num: - INFO(f"sublabel {idx} should have {std_num} class, but data only have {sublabel_num} class", screen=True) - return False - return True - def pretrain(model, X, Z): pass -def train(model, abducer, X, Z, Y, epochs = 5, sample_num = -1, verbose = -1): +def train(model, abducer, train_data, test_data, epochs = 5, sample_num = -1, verbose = -1): + X, Z, Y = train_data + test_X, test_Z, test_Y = test_data + # Set default parameters if sample_num == -1: sample_num = len(X) @@ -146,10 +89,10 @@ def train(model, abducer, X, Z, Y, epochs = 5, sample_num = -1, verbose = -1): preds_res = predict_func(X) abduced_Z = abduce_func(preds_res, Y) - abl_acc = get_abl_acc(Y, preds_res['cls'], abducer.kb.logic_forward) + abl_acc = get_abl_acc(preds_res['cls'], Y, abducer.kb.logic_forward) if(char_acc_flag): - ori_char_acc = get_char_acc(Z, preds_res['cls']) - abd_char_acc = get_char_acc(abduced_Z, preds_res['cls']) + ori_char_acc = get_char_acc(preds_res['cls'], Z) + abd_char_acc = get_char_acc(preds_res['cls'], abduced_Z) INFO('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc, ' ori_char_acc:', ori_char_acc, ' abd_char_acc:', abd_char_acc) else: INFO('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc) @@ -163,49 +106,5 @@ def train(model, abducer, X, Z, Y, epochs = 5, sample_num = -1, verbose = -1): return abl_acc -# def train(model, abducer, X, Y, C = None, epochs = 10, sample_num = -1, verbose = -1, check_sublabel = True): -# # Set default parameters -# if sample_num == -1: -# sample_num = len(X) - -# if verbose < 1: -# verbose = epochs - -# if C is None: -# C = [None] * len(X) - -# # Set function running time recorder -# valid_func = clocker(model.valid) -# predict_func = clocker(model.predict) -# train_func = clocker(model.train) - -# abduce_func = clocker(abducer.batch_abduce) - -# X_bak = X -# Y_bak = Y -# C_bak = C - -# # Abductive learning train process -# res = {} -# for epoch_idx in range(epochs): -# X, Y, C = block_sample(X_bak, Y_bak, C_bak, sample_num, epoch_idx) -# preds_res = predict_func(X) -# abduced_Y = abduce_func(preds_res, C) -# finetune_X, finetune_Y = filter_data(X, abduced_Y) -# score, score_list = valid_func(X, Y) -# if ((epoch_idx + 1) % verbose == 0) or (epoch_idx == epochs - 1): -# res = result_statistics(preds_res["cls"], Y, abduced_Y) -# INFO(res) - -# if check_sublabel and (not is_all_sublabel_exist(finetune_Y, model.label_lists)): -# INFO("There is some sub label missing", len(finetune_Y)) -# break - -# if len(finetune_X) > 0: -# train_func(finetune_X, finetune_Y)#, n_epoch = 10) -# else: -# INFO("lack of data, all abduced failed", len(finetune_X)) -# return res - if __name__ == "__main__": pass From acbaa9f2e4fb63410d09c17153b0fb1efaf771bb Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 22 Nov 2022 19:04:15 +0800 Subject: [PATCH 074/601] Update kb.py --- abducer/kb.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index e987d15..b21f97a 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -119,7 +119,7 @@ class add_KB(ClsKB): class hwf_KB(ClsKB): def __init__(self, GKB_flag = False, \ - pseudo_label_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', 'times', 'div'], \ + pseudo_label_list = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', 'times', 'div'], \ len_list = [1, 3, 5, 7]): super().__init__(GKB_flag, pseudo_label_list, len_list) @@ -127,7 +127,7 @@ class hwf_KB(ClsKB): if len(formula) % 2 == 0: return False for i in range(len(formula)): - if i % 2 == 0 and formula[i] not in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']: + if i % 2 == 0 and formula[i] not in ['1', '2', '3', '4', '5', '6', '7', '8', '9']: return False if i % 2 != 0 and formula[i] not in ['+', '-', 'times', 'div']: return False @@ -136,12 +136,9 @@ class hwf_KB(ClsKB): def logic_forward(self, formula): if not self.valid_candidate(formula): return np.inf - try: - mapping = {'0':'0', '1':'1', '2':'2', '3':'3', '4':'4', '5':'5', '6':'6', '7':'7', '8':'8', '9':'9', '+':'+', '-':'-', 'times':'*', 'div':'/'} - formula = [mapping[f] for f in formula] - return round(eval(''.join(formula)), 2) - except ZeroDivisionError: - return np.inf + mapping = {'1':'1', '2':'2', '3':'3', '4':'4', '5':'5', '6':'6', '7':'7', '8':'8', '9':'9', '+':'+', '-':'-', 'times':'*', 'div':'/'} + formula = [mapping[f] for f in formula] + return round(eval(''.join(formula)), 2) class RegKB(KBBase): From 469407e8ed9849a172047430490a80b93c3ed417 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 22 Nov 2022 22:13:30 +0800 Subject: [PATCH 075/601] Update framework.py --- framework.py | 55 +++++++++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/framework.py b/framework.py index 7f0debf..7e36b1b 100644 --- a/framework.py +++ b/framework.py @@ -28,28 +28,27 @@ def block_sample(X, Z, Y, sample_num, epoch_idx): return X, Z, Y -def get_taglist(self, Z): - tmp = [[str(x) for x in label] for label in Z] - tmp = sorted(list(set(tmp))) - return tmp - -def get_abl_acc(pred_Z, Y, logic_forward): - abl_acc = 0 +def result_statistics(pred_Z, Z, Y, logic_forward, char_acc_flag): + result = {} + if char_acc_flag: + char_acc_num = 0 + char_num = 0 + for pred_z, z in zip(pred_Z, Z): + char_num += len(z) + for zidx in range(len(z)): + if(pred_z[zidx] == z[zidx]): + char_acc_num += 1 + char_acc = char_acc_num / char_num + result["Character level accuracy"] = char_acc + + abl_acc_num = 0 for pred_z, y in zip(pred_Z, Y): if(logic_forward(pred_z) == y): - abl_acc += 1 - return abl_acc / len(Y) - -def get_char_acc(Z, pred_Z): - char_acc = 0 - char_num = 0 - for pred_z, z in zip(pred_Z, Z): - char_num += len(z) - for zidx in range(len(z)): - if(pred_z[zidx] == z[zidx]): - char_acc += 1 - return char_acc / char_num - + abl_acc_num += 1 + abl_acc = abl_acc_num / len(Y) + result["ABL accuracy"] = abl_acc + + return result def filter_data(X, abduced_Z): finetune_Z = [] @@ -63,7 +62,7 @@ def filter_data(X, abduced_Z): def pretrain(model, X, Z): pass -def train(model, abducer, train_data, test_data, epochs = 5, sample_num = -1, verbose = -1): +def train(model, abducer, train_data, test_data, epochs = 50, sample_num = -1, verbose = -1): X, Z, Y = train_data test_X, test_Z, test_Y = test_data @@ -89,13 +88,9 @@ def train(model, abducer, train_data, test_data, epochs = 5, sample_num = -1, ve preds_res = predict_func(X) abduced_Z = abduce_func(preds_res, Y) - abl_acc = get_abl_acc(preds_res['cls'], Y, abducer.kb.logic_forward) - if(char_acc_flag): - ori_char_acc = get_char_acc(preds_res['cls'], Z) - abd_char_acc = get_char_acc(preds_res['cls'], abduced_Z) - INFO('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc, ' ori_char_acc:', ori_char_acc, ' abd_char_acc:', abd_char_acc) - else: - INFO('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc) + if ((epoch_idx + 1) % verbose == 0) or (epoch_idx == epochs - 1): + res = result_statistics(preds_res['cls'], Z, Y, abducer.kb.logic_forward, char_acc_flag) + INFO('epoch: ', epoch_idx + 1, ' ', res) finetune_X, finetune_Z = filter_data(X, abduced_Z) if len(finetune_X) > 0: @@ -104,7 +99,9 @@ def train(model, abducer, train_data, test_data, epochs = 5, sample_num = -1, ve else: INFO("lack of data, all abduced failed", len(finetune_X)) - return abl_acc + return res if __name__ == "__main__": pass + + From d252128d0f3703e0b56bf99d555d82e60346123e Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 22 Nov 2022 22:18:22 +0800 Subject: [PATCH 076/601] Update example.py --- example.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/example.py b/example.py index dad33f7..7ceaeff 100644 --- a/example.py +++ b/example.py @@ -15,7 +15,7 @@ import framework import torch.nn as nn import torch -from models.lenet5 import LeNet5 +from models.lenet5 import LeNet5, SymbolNet from models.basic_model import BasicModel from models.wabl_models import WABLBasicModel @@ -28,16 +28,20 @@ from datasets.hwf.get_hwf import get_hwf def run_test(): - kb = add_KB() - # kb = hwf_KB() + # kb = add_KB(True) + kb = hwf_KB(True) abducer = AbducerBase(kb) recorder = logger() - train_X, train_Z, train_Y = get_mnist_add(train = True, get_pseudo_label = True) - test_X, test_Z, test_Y = get_mnist_add(train = False, get_pseudo_label = True) + # train_X, train_Z, train_Y = get_mnist_add(train = True, get_pseudo_label = True) + # test_X, test_Z, test_Y = get_mnist_add(train = False, get_pseudo_label = True) + + train_data = get_hwf(train = True, get_pseudo_label = True) + test_data = get_hwf(train = False, get_pseudo_label = True) - cls = LeNet5(num_classes=len(kb.pseudo_label_list), image_size=(train_X[0][0].shape[1:])) + # cls = LeNet5(num_classes=len(kb.pseudo_label_list), image_size=(train_data[0][0][0].shape[1:])) + cls = SymbolNet(num_classes=len(kb.pseudo_label_list)) criterion = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(cls.parameters(), lr=0.001, betas=(0.9, 0.99)) @@ -46,12 +50,11 @@ def run_test(): base_model = BasicModel(cls, criterion, optimizer, device, save_interval=1, save_dir=recorder.save_dir, num_epochs=1, recorder=recorder) model = WABLBasicModel(base_model, kb.pseudo_label_list) - res = framework.train(model, abducer, train_X, train_Z, train_Y, sample_num = 10000, verbose = 1) - recorder.print("abl_acc is ", res) + res = framework.train(model, abducer, train_data, test_data, sample_num = 10000, verbose = 1) + recorder.print(res) recorder.dump() return True if __name__ == "__main__": run_test() - From c3a7112204ff48903a232591781beb5531ec50c5 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 23 Nov 2022 10:06:05 +0800 Subject: [PATCH 077/601] Update abducer_base.py --- abducer/abducer_base.py | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 284ebe4..83826a6 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -10,12 +10,15 @@ # #================================================================# +import sys +sys.path.append("..") + import abc -# from kb import add_KB, hwf_KB from abducer.kb import add_KB, hwf_KB import numpy as np from itertools import product, combinations +import time class AbducerBase(abc.ABC): def __init__(self, kb, dist_func = 'confidence', cache = True): @@ -23,8 +26,10 @@ class AbducerBase(abc.ABC): assert(dist_func == 'hamming' or dist_func == 'confidence') self.dist_func = dist_func self.cache = cache - self.cache_min_address_num = {} - self.cache_candidates = {} + + if self.cache: + self.cache_min_address_num = {} + self.cache_candidates = {} def hamming_dist(self, A, B): B = np.array(B) @@ -79,7 +84,9 @@ class AbducerBase(abc.ABC): if self.kb.GKB_flag: all_candidates = self.kb.get_candidates(ans, len(pred_res)) if len(all_candidates) == 0: - return [] + candidates = [] + min_address_num = 0 + address_num = 0 else: cost_list = self.hamming_dist(pred_res, all_candidates) min_address_num = np.min(cost_list) @@ -108,30 +115,30 @@ class AbducerBase(abc.ABC): pred_res_array[np.array(address_idx)] = c if self.kb.logic_forward(pred_res_array) == key: new_candidates.append(pred_res_array) - return new_candidates, address_num + return new_candidates def get_abduce_candidates(self, pred_res, key, max_address_num, require_more_address): - candidates = [] + print(pred_res) for address_num in range(len(pred_res) + 1): - if address_num > max_address_num: - return [], None, None - if address_num == 0: if abs(self.kb.logic_forward(pred_res) - key) <= 1e-3: candidates.append(pred_res) else: - new_candidates, address_num = self.address(address_num, pred_res, key) + new_candidates = self.address(address_num, pred_res, key) candidates += new_candidates if len(candidates) > 0: min_address_num = address_num break + + if address_num >= max_address_num: + return [], 0, 0 for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): if address_num > max_address_num: return candidates, min_address_num, address_num - 1 - new_candidates, address_num = self.address(address_num, pred_res, key) + new_candidates = self.address(address_num, pred_res, key) candidates += new_candidates return candidates, min_address_num, address_num @@ -163,7 +170,7 @@ if __name__ == '__main__': abd = AbducerBase(kb, 'hamming') res = abd.abduce((['5', '+', '2'], None, 3), max_address_num = 2, require_more_address = 0) print(res) - res = abd.abduce((['5', '+', '2'], None, 3.09), max_address_num = 2, require_more_address = 0) + res = abd.abduce((['5', '+', '2'], None, 64), max_address_num = 3, require_more_address = 0) print(res) res = abd.abduce((['5', '+', '2'], None, 1.67), max_address_num = 3, require_more_address = 0) print(res) From 18fc1be9fa2b25da7690182f675757bbfc78345b Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 23 Nov 2022 13:40:47 +0800 Subject: [PATCH 078/601] Speed up get_abduce_candidates --- abducer/abducer_base.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 83826a6..63a3c73 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -110,11 +110,13 @@ class AbducerBase(abc.ABC): address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) for address_idx in address_idx_list: for c in all_address_candidate: - pred_res_array = np.array(pred_res) - if np.count_nonzero(np.array(c) != pred_res_array[np.array(address_idx)]) == address_num: - pred_res_array[np.array(address_idx)] = c - if self.kb.logic_forward(pred_res_array) == key: - new_candidates.append(pred_res_array) + address_list = [pred_res[i] for i in address_idx] + if(sum([address_list[i] == c[i] for i in range(address_num)]) == 0): + candidate = pred_res.copy() + for i, idx in enumerate(address_idx): + candidate[idx] = c[i] + if self.kb.logic_forward(candidate) == key: + new_candidates.append(candidate) return new_candidates def get_abduce_candidates(self, pred_res, key, max_address_num, require_more_address): From 66149d92f78b4c33301907170cb11407401019c8 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 23 Nov 2022 13:57:39 +0800 Subject: [PATCH 079/601] Update framework.py --- framework.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/framework.py b/framework.py index 7e36b1b..ed013b7 100644 --- a/framework.py +++ b/framework.py @@ -63,7 +63,7 @@ def pretrain(model, X, Z): pass def train(model, abducer, train_data, test_data, epochs = 50, sample_num = -1, verbose = -1): - X, Z, Y = train_data + train_X, train_Z, train_Y = train_data test_X, test_Z, test_Y = test_data # Set default parameters @@ -74,9 +74,9 @@ def train(model, abducer, train_data, test_data, epochs = 50, sample_num = -1, v verbose = epochs char_acc_flag = 1 - if Z == None: + if train_Z == None: char_acc_flag = 0 - Z = [None] * len(X) + train_Z = [None] * len(X) predict_func = clocker(model.predict) train_func = clocker(model.train) @@ -84,7 +84,7 @@ def train(model, abducer, train_data, test_data, epochs = 50, sample_num = -1, v # Abductive learning train process for epoch_idx in range(epochs): - X, Z, Y = block_sample(X, Z, Y, sample_num, epoch_idx) + X, Z, Y = block_sample(train_X, train_Z, train_Y, sample_num, epoch_idx) preds_res = predict_func(X) abduced_Z = abduce_func(preds_res, Y) From 5f940cbda93220aa56216376cbc208c388f895a6 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 24 Nov 2022 17:42:16 +0800 Subject: [PATCH 080/601] Update kb.py --- abducer/kb.py | 327 +++++++++++++++++--------------------------------- 1 file changed, 108 insertions(+), 219 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index b21f97a..f26b363 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -1,8 +1,8 @@ # coding: utf-8 #================================================================# -# Copyright (C) 2021 LAMDA All rights reserved. +# Copyright (C) 2021 Freecss All rights reserved. # -# File Name :kb.py +# File Name :abducer_base.py # Author :freecss # Email :karlfreecss@gmail.com # Created Date :2021/06/03 @@ -10,249 +10,138 @@ # #================================================================# -from abc import ABC, abstractmethod -import bisect -import copy -import numpy as np - -from collections import defaultdict -from itertools import product - -class KBBase(ABC): - def __init__(self): - pass - - @abstractmethod - def get_candidates(self): - pass - - @abstractmethod - def get_all_candidates(self): - pass - - @abstractmethod - def logic_forward(self): - pass - - def _length(self, length): - if length is None: - length = list(self.base.keys()) - if type(length) is int: - length = [length] - return length - - def __len__(self): - pass +import sys +sys.path.append("..") +import abc +from abducer.kb import add_KB, hwf_KB, add_prolog_KB +import numpy as np -class ClsKB(KBBase): - def __init__(self, GKB_flag = False, pseudo_label_list = None, len_list = None): - super().__init__() - self.GKB_flag = GKB_flag - self.pseudo_label_list = pseudo_label_list - self.len_list = len_list - - if GKB_flag: - # self.base = np.load('abducer/hwf.npy', allow_pickle=True).item() - self.base = {} - X, Y = self.get_GKB(self.pseudo_label_list, self.len_list) - for x, y in zip(X, Y): - self.base.setdefault(len(x), defaultdict(list))[y].append(x) - - def get_GKB(self, pseudo_label_list, len_list): - all_X = [] - for len in len_list: - all_X += list(product(pseudo_label_list, repeat = len)) - - X = [] - Y = [] - for x in all_X: - y = self.logic_forward(x) - if y != np.inf: - X.append(x) - Y.append(y) - return X, Y - - def logic_forward(self): - pass +from itertools import product, combinations +import time - def get_candidates(self, key, length = None): - if not self.GKB_flag or self.base == {}: - return [] +class AbducerBase(abc.ABC): + def __init__(self, kb, dist_func = 'confidence', cache = True): + self.kb = kb + assert(dist_func == 'hamming' or dist_func == 'confidence') + self.dist_func = dist_func + self.cache = cache - if key is None: - return self.get_all_candidates() - - if type(length) is int and length not in self.len_list: - return [] - length = self._length(length) - return sum([self.base[l][key] for l in length], []) - - def get_all_candidates(self): - if not self.GKB_flag or self.base == {}: + if self.cache: + self.cache_min_address_num = {} + self.cache_candidates = {} + + def hamming_dist(self, A, B): + B = np.array(B) + A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) + return np.sum(A != B, axis = 1) + + def confidence_dist(self, A, B): + mapping = dict(zip(self.kb.pseudo_label_list, list(range(len(self.kb.pseudo_label_list))))) + B = [list(map(lambda x : mapping[x], b)) for b in B] + + B = np.array(B) + A = np.clip(A, 1e-9, 1) + A = np.expand_dims(A, axis=0) + A = A.repeat(axis=0, repeats=(len(B))) + rows = np.array(range(len(B))) + rows = np.expand_dims(rows, axis = 1).repeat(axis = 1, repeats = len(B[0])) + cols = np.array(range(len(B[0]))) + cols = np.expand_dims(cols, axis = 0).repeat(axis = 0, repeats = len(B)) + return 1 - np.prod(A[rows, cols, B], axis = 1) + + + def get_cost_list(self, pred_res, pred_res_prob, candidates): + if self.dist_func == 'hamming': + return self.hamming_dist(pred_res, candidates) + elif self.dist_func == 'confidence': + return self.confidence_dist(pred_res_prob, candidates) + + def get_min_cost_candidate(self, pred_res, pred_res_prob, candidates): + if len(candidates) == 0: return [] + elif len(candidates) == 1: + return candidates[0] else: - return sum([sum(v.values(), []) for v in self.base.values()], []) - - def _dict_len(self, dic): - if not self.GKB_flag: - return 0 - else: - return sum(len(c) for c in dic.values()) - - def __len__(self): - if not self.GKB_flag: - return 0 + cost_list = self.get_cost_list(pred_res, pred_res_prob, candidates) + min_address_num = np.min(cost_list) + idxs = np.where(cost_list == min_address_num)[0] + return [candidates[idx] for idx in idxs][0] + + def filter_all_candidates(self, pred_res, all_candidates, max_address_num, require_more_address): + if len(all_candidates) == 0: + candidates = [] + min_address_num = 0 + address_num = 0 else: - return sum(self._dict_len(v) for v in self.base.values()) - - -class add_KB(ClsKB): - def __init__(self, GKB_flag = False, \ - pseudo_label_list = list(range(10)), \ - len_list = [2]): - super().__init__(GKB_flag, pseudo_label_list, len_list) - - def logic_forward(self, nums): - return sum(nums) - - -class hwf_KB(ClsKB): - def __init__(self, GKB_flag = False, \ - pseudo_label_list = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', 'times', 'div'], \ - len_list = [1, 3, 5, 7]): - super().__init__(GKB_flag, pseudo_label_list, len_list) + cost_list = self.hamming_dist(pred_res, all_candidates) + min_address_num = np.min(cost_list) + address_num = min(max_address_num, min_address_num + require_more_address) + idxs = np.where(cost_list <= address_num)[0] + candidates = [all_candidates[idx] for idx in idxs] + return candidates, min_address_num, address_num + + def abduce(self, data, max_address_num = -1, require_more_address = 0): + pred_res, pred_res_prob, ans = data + + if self.cache and (tuple(pred_res), ans) in self.cache_min_address_num: + address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), ans)] + require_more_address) + if (tuple(pred_res), ans, address_num) in self.cache_candidates: + candidates = self.cache_candidates[(tuple(pred_res), ans, address_num)] + candidate = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) + return candidate - def valid_candidate(self, formula): - if len(formula) % 2 == 0: - return False - for i in range(len(formula)): - if i % 2 == 0 and formula[i] not in ['1', '2', '3', '4', '5', '6', '7', '8', '9']: - return False - if i % 2 != 0 and formula[i] not in ['+', '-', 'times', 'div']: - return False - return True - - def logic_forward(self, formula): - if not self.valid_candidate(formula): - return np.inf - mapping = {'1':'1', '2':'2', '3':'3', '4':'4', '5':'5', '6':'6', '7':'7', '8':'8', '9':'9', '+':'+', '-':'-', 'times':'*', 'div':'/'} - formula = [mapping[f] for f in formula] - return round(eval(''.join(formula)), 2) - - -class RegKB(KBBase): - def __init__(self, GKB_flag = False, X = None, Y = None): - super().__init__() - tmp_dict = {} - for x, y in zip(X, Y): - tmp_dict.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) - - self.base = {} - for l in tmp_dict.keys(): - data = sorted(list(zip(tmp_dict[l].keys(), tmp_dict[l].values()))) - X = [x for y, x in data] - Y = [y for y, x in data] - self.base[l] = (X, Y) + candidates, min_address_num, address_num = self.kb.abduce_candidates(pred_res, ans, max_address_num, require_more_address) + + if self.cache: + self.cache_min_address_num[(tuple(pred_res), ans)] = min_address_num + self.cache_candidates[(tuple(pred_res), ans, address_num)] = candidates - def valid_candidate(self): - pass - - def logic_forward(self): - pass + candidate = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) + return candidate - - def get_candidates(self, key, length = None): - if key is None: - return self.get_all_candidates() - - length = self._length(length) - - min_err = 999999 - candidates = [] - for l in length: - X, Y = self.base[l] + + def batch_abduce(self, Z, Y, max_address_num = -1, require_more_address = 0): + return [ + self.abduce((z, prob, y), max_address_num, require_more_address)\ + for z, prob, y in zip(Z['cls'], Z['prob'], Y) + ] - idx = bisect.bisect_left(Y, key) - begin = max(0, idx - 1) - end = min(idx + 2, len(X)) - - for idx in range(begin, end): - err = abs(Y[idx] - key) - if abs(err - min_err) < 1e-9: - candidates.extend(X[idx]) - elif err < min_err: - candidates = copy.deepcopy(X[idx]) - min_err = err - return candidates - - def get_all_candidates(self): - return sum([sum(D[0], []) for D in self.base.values()], []) - - def __len__(self): - return sum([sum(len(x) for x in D[0]) for D in self.base.values()]) + def __call__(self, Z, Y, max_address_num = -1, require_more_address = 0): + return self.batch_abduce(Z, Y, max_address_num, require_more_address) + -import time -if __name__ == "__main__": - # With ground KB +if __name__ == '__main__': kb = add_KB(GKB_flag = True) - print('len(kb):', len(kb)) - res = kb.get_candidates(0) + abd = AbducerBase(kb, 'hamming') + res = abd.abduce(([1, 1], None, 17), max_address_num = 2, require_more_address = 0) print(res) - res = kb.get_candidates(18) + res = abd.abduce(([1, 1], None, 17), max_address_num = 1, require_more_address = 0) print(res) - res = kb.get_candidates(18) - print(res) - res = kb.get_candidates(7) + res = abd.abduce(([1, 1], None, 20), max_address_num = 2, require_more_address = 0) print(res) print() - # Without ground KB - kb = add_KB() - print('len(kb):', len(kb)) - res = kb.get_candidates(0) - print(res) - res = kb.get_candidates(18, length = 2) + kb = add_prolog_KB() + abd = AbducerBase(kb, 'hamming') + res = abd.abduce(([1, 1], None, 17), max_address_num = 2, require_more_address = 0) print(res) - res = kb.get_candidates(18, length = 8) + res = abd.abduce(([1, 1], None, 17), max_address_num = 1, require_more_address = 0) print(res) - res = kb.get_candidates(7, length = 3) + res = abd.abduce(([1, 1], None, 20), max_address_num = 2, require_more_address = 0) print(res) print() - start = time.time() - kb = hwf_KB(GKB_flag = True) - print(time.time() - start) - print('len(kb):', len(kb)) - res = kb.get_candidates(2, length = 1) + kb = hwf_KB(len_list = [1, 3, 5]) + abd = AbducerBase(kb, 'hamming') + res = abd.abduce((['5', '+', '2'], None, 3), max_address_num = 2, require_more_address = 0) + print(res) + res = abd.abduce((['5', '+', '2'], None, 64), max_address_num = 3, require_more_address = 0) print(res) - res = kb.get_candidates(1, length = 3) + res = abd.abduce((['5', '+', '2'], None, 1.67), max_address_num = 3, require_more_address = 0) print(res) - res = kb.get_candidates(3.67, length = 5) + res = abd.abduce((['5', '8', '8', '8', '8'], None, 3.17), max_address_num = 5, require_more_address = 3) print(res) print() - # X = ["1+1", "0+1", "1+0", "2+0", "1+0+1"] - # Y = [2, 1, 1, 2, 2] - # kb = ClsKB(X, Y) - # print('len(kb):', len(kb)) - # res = kb.get_candidates(2, 5) - # print(res) - # res = kb.get_candidates(2, 3) - # print(res) - # res = kb.get_candidates(None) - # print(res) - # print() - - # X = ["1+1", "0+1", "1+0", "2+0", "1+0.5", "0.75+0.75"] - # Y = [2, 1, 1, 2, 1.5, 1.5] - # kb = RegKB(X, Y) - # print('len(kb):', len(kb)) - # res = kb.get_candidates(1.6) - # print(res) - # res = kb.get_candidates(1.6, length = 9) - # print(res) - # res = kb.get_candidates(None) - # print(res) - From abb7fb4a1eb0927a2e96abcf8d6baa91e08a9ac1 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 24 Nov 2022 17:42:27 +0800 Subject: [PATCH 081/601] Update kb.py --- abducer/kb.py | 403 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 310 insertions(+), 93 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index f26b363..2600f8b 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -1,8 +1,8 @@ # coding: utf-8 #================================================================# -# Copyright (C) 2021 Freecss All rights reserved. +# Copyright (C) 2021 LAMDA All rights reserved. # -# File Name :abducer_base.py +# File Name :kb.py # Author :freecss # Email :karlfreecss@gmail.com # Created Date :2021/06/03 @@ -10,63 +10,27 @@ # #================================================================# -import sys -sys.path.append("..") - -import abc -from abducer.kb import add_KB, hwf_KB, add_prolog_KB +from abc import ABC, abstractmethod +import bisect +import copy import numpy as np +from collections import defaultdict from itertools import product, combinations -import time -class AbducerBase(abc.ABC): - def __init__(self, kb, dist_func = 'confidence', cache = True): - self.kb = kb - assert(dist_func == 'hamming' or dist_func == 'confidence') - self.dist_func = dist_func - self.cache = cache - - if self.cache: - self.cache_min_address_num = {} - self.cache_candidates = {} +import pyswip - def hamming_dist(self, A, B): - B = np.array(B) - A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) - return np.sum(A != B, axis = 1) +class KBBase(ABC): + def __init__(self): + pass - def confidence_dist(self, A, B): - mapping = dict(zip(self.kb.pseudo_label_list, list(range(len(self.kb.pseudo_label_list))))) - B = [list(map(lambda x : mapping[x], b)) for b in B] + @abstractmethod + def logic_forward(self): + pass - B = np.array(B) - A = np.clip(A, 1e-9, 1) - A = np.expand_dims(A, axis=0) - A = A.repeat(axis=0, repeats=(len(B))) - rows = np.array(range(len(B))) - rows = np.expand_dims(rows, axis = 1).repeat(axis = 1, repeats = len(B[0])) - cols = np.array(range(len(B[0]))) - cols = np.expand_dims(cols, axis = 0).repeat(axis = 0, repeats = len(B)) - return 1 - np.prod(A[rows, cols, B], axis = 1) - - - def get_cost_list(self, pred_res, pred_res_prob, candidates): - if self.dist_func == 'hamming': - return self.hamming_dist(pred_res, candidates) - elif self.dist_func == 'confidence': - return self.confidence_dist(pred_res_prob, candidates) - - def get_min_cost_candidate(self, pred_res, pred_res_prob, candidates): - if len(candidates) == 0: - return [] - elif len(candidates) == 1: - return candidates[0] - else: - cost_list = self.get_cost_list(pred_res, pred_res_prob, candidates) - min_address_num = np.min(cost_list) - idxs = np.where(cost_list == min_address_num)[0] - return [candidates[idx] for idx in idxs][0] + @abstractmethod + def abduce_candidates(self): + pass def filter_all_candidates(self, pred_res, all_candidates, max_address_num, require_more_address): if len(all_candidates) == 0: @@ -80,68 +44,321 @@ class AbducerBase(abc.ABC): idxs = np.where(cost_list <= address_num)[0] candidates = [all_candidates[idx] for idx in idxs] return candidates, min_address_num, address_num + + def hamming_dist(self, A, B): + B = np.array(B) + A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) + return np.sum(A != B, axis = 1) + + def __len__(self): + pass + +class ClsKB(KBBase): + def __init__(self, GKB_flag = False, pseudo_label_list = None, len_list = None): + super().__init__() + self.GKB_flag = GKB_flag + self.pseudo_label_list = pseudo_label_list + self.len_list = len_list + self.prolog_flag = False + + if GKB_flag: + # self.base = np.load('abducer/hwf.npy', allow_pickle=True).item() + self.base = {} + X, Y = self.get_GKB(self.pseudo_label_list, self.len_list) + for x, y in zip(X, Y): + self.base.setdefault(len(x), defaultdict(list))[y].append(x) + else: + self.all_address_candidate_dict = {} + for address_num in range(1, max(self.len_list) + 1): + self.all_address_candidate_dict[address_num] = list(product(self.pseudo_label_list, repeat = address_num)) + + def get_GKB(self, pseudo_label_list, len_list): + all_X = [] + for len in len_list: + all_X += list(product(pseudo_label_list, repeat = len)) + + X = [] + Y = [] + for x in all_X: + y = self.logic_forward(x) + if y != np.inf: + X.append(x) + Y.append(y) + return X, Y + + def logic_forward(self): + pass + + def abduce_candidates(self, pred_res, key, max_address_num = -1, require_more_address = 0): + if max_address_num == -1: + max_address_num = len(pred_res) + if self.GKB_flag: + all_candidates = self.get_candidates_GKB(key, len(pred_res)) + return self.filter_all_candidates(pred_res, all_candidates, max_address_num, require_more_address) + else: + return self.abduction(pred_res, key, max_address_num, require_more_address) - def abduce(self, data, max_address_num = -1, require_more_address = 0): - pred_res, pred_res_prob, ans = data - if self.cache and (tuple(pred_res), ans) in self.cache_min_address_num: - address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), ans)] + require_more_address) - if (tuple(pred_res), ans, address_num) in self.cache_candidates: - candidates = self.cache_candidates[(tuple(pred_res), ans, address_num)] - candidate = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) - return candidate + + def get_candidates_GKB(self, key, length = None): + if self.base == {}: + return [] - candidates, min_address_num, address_num = self.kb.abduce_candidates(pred_res, ans, max_address_num, require_more_address) + if key is None: + return self.get_all_candidates() + + if length is None: + length = list(self.base.keys()) + elif type(length) is int and length not in self.len_list: + return [] + else: + length = [length] + + return sum([self.base[l][key] for l in length], []) + + def get_all_candidates(self): + if self.base == {}: + return [] + else: + return sum([sum(v.values(), []) for v in self.base.values()], []) + + + + + + def abduction(self, pred_res, key, max_address_num, require_more_address): + candidates = [] + for address_num in range(len(pred_res) + 1): + if address_num == 0: + if abs(self.logic_forward(pred_res) - key) <= 1e-3: + candidates.append(pred_res) + else: + new_candidates = self.address(address_num, pred_res, key) + candidates += new_candidates + + if len(candidates) > 0: + min_address_num = address_num + break + + if address_num >= max_address_num: + return [], 0, 0 - if self.cache: - self.cache_min_address_num[(tuple(pred_res), ans)] = min_address_num - self.cache_candidates[(tuple(pred_res), ans, address_num)] = candidates + for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): + if address_num > max_address_num: + return candidates, min_address_num, address_num - 1 + new_candidates = self.address(address_num, pred_res, key) + candidates += new_candidates - candidate = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) - return candidate + return candidates, min_address_num, address_num + + def address(self, address_num, pred_res, key): + new_candidates = [] + all_address_candidate = self.all_address_candidate_dict[address_num] + address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) + for address_idx in address_idx_list: + for c in all_address_candidate: + address_list = [pred_res[i] for i in address_idx] + if(sum([address_list[i] == c[i] for i in range(address_num)]) == 0): + candidate = pred_res.copy() + for i, idx in enumerate(address_idx): + candidate[idx] = c[i] + if self.logic_forward(candidate) == key: + new_candidates.append(candidate) + return new_candidates + - - def batch_abduce(self, Z, Y, max_address_num = -1, require_more_address = 0): - return [ - self.abduce((z, prob, y), max_address_num, require_more_address)\ - for z, prob, y in zip(Z['cls'], Z['prob'], Y) - ] - def __call__(self, Z, Y, max_address_num = -1, require_more_address = 0): - return self.batch_abduce(Z, Y, max_address_num, require_more_address) + def _dict_len(self, dic): + if not self.GKB_flag: + return 0 + else: + return sum(len(c) for c in dic.values()) + + def __len__(self): + if not self.GKB_flag: + return 0 + else: + return sum(self._dict_len(v) for v in self.base.values()) + + +class add_KB(ClsKB): + def __init__(self, GKB_flag = False, \ + pseudo_label_list = list(range(10)), \ + len_list = [2]): + super().__init__(GKB_flag, pseudo_label_list, len_list) + + def logic_forward(self, nums): + return sum(nums) + +class hwf_KB(ClsKB): + def __init__(self, GKB_flag = False, \ + pseudo_label_list = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', 'times', 'div'], \ + len_list = [1, 3, 5, 7]): + super().__init__(GKB_flag, pseudo_label_list, len_list) + + def valid_candidate(self, formula): + if len(formula) % 2 == 0: + return False + for i in range(len(formula)): + if i % 2 == 0 and formula[i] not in ['1', '2', '3', '4', '5', '6', '7', '8', '9']: + return False + if i % 2 != 0 and formula[i] not in ['+', '-', 'times', 'div']: + return False + return True + + def logic_forward(self, formula): + if not self.valid_candidate(formula): + return np.inf + mapping = {'1':'1', '2':'2', '3':'3', '4':'4', '5':'5', '6':'6', '7':'7', '8':'8', '9':'9', '+':'+', '-':'-', 'times':'*', 'div':'/'} + formula = [mapping[f] for f in formula] + return round(eval(''.join(formula)), 2) + + + + + +class prolog_KB(KBBase): + def __init__(self, pseudo_label_list): + super().__init__() + self.pseudo_label_list = pseudo_label_list + self.prolog = pyswip.Prolog() + for i in self.pseudo_label_list: + self.prolog.assertz("pseudo_label(%s)" % i) + self.prolog_flag = True + + def logic_forward(self): + pass + + def abduce_candidates(self, pred_res, key, max_address_num = -1, require_more_address = 0): + if max_address_num == -1: + max_address_num = len(pred_res) + all_candidates = self.get_candidates_prolog(key) + return self.filter_all_candidates(pred_res, all_candidates, max_address_num, require_more_address) + + +class add_prolog_KB(prolog_KB): + def __init__(self, pseudo_label_list = list(range(10))): + super().__init__(pseudo_label_list) + self.prolog.assertz("addition(Z1, Z2, Res) :- pseudo_label(Z1), pseudo_label(Z2), Res is Z1+Z2") + + def logic_forward(self, nums): + return list(self.prolog.query("addition(%s, %s, Res)." %(nums[0], nums[1])))[0]['Res'] + + def get_candidates_prolog(self, key): + return [(z['Z1'], z['Z2']) for z in list(self.prolog.query("addition(Z1, Z2, %s)." % key))] + + +class RegKB(KBBase): + def __init__(self, GKB_flag = False, X = None, Y = None): + super().__init__() + tmp_dict = {} + for x, y in zip(X, Y): + tmp_dict.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) + + self.base = {} + for l in tmp_dict.keys(): + data = sorted(list(zip(tmp_dict[l].keys(), tmp_dict[l].values()))) + X = [x for y, x in data] + Y = [y for y, x in data] + self.base[l] = (X, Y) + + def valid_candidate(self): + pass + + def logic_forward(self): + pass + + def abduce_candidates(self, key, length = None): + if key is None: + return self.get_all_candidates() + + length = self._length(length) + + min_err = 999999 + candidates = [] + for l in length: + X, Y = self.base[l] -if __name__ == '__main__': + idx = bisect.bisect_left(Y, key) + begin = max(0, idx - 1) + end = min(idx + 2, len(X)) + + for idx in range(begin, end): + err = abs(Y[idx] - key) + if abs(err - min_err) < 1e-9: + candidates.extend(X[idx]) + elif err < min_err: + candidates = copy.deepcopy(X[idx]) + min_err = err + return candidates + + def get_all_candidates(self): + return sum([sum(D[0], []) for D in self.base.values()], []) + + def __len__(self): + return sum([sum(len(x) for x in D[0]) for D in self.base.values()]) + +import time +if __name__ == "__main__": + # With ground KB kb = add_KB(GKB_flag = True) - abd = AbducerBase(kb, 'hamming') - res = abd.abduce(([1, 1], None, 17), max_address_num = 2, require_more_address = 0) + print('len(kb):', len(kb)) + res = kb.get_candidates_GKB(0) print(res) - res = abd.abduce(([1, 1], None, 17), max_address_num = 1, require_more_address = 0) + res = kb.get_candidates_GKB(18) print(res) - res = abd.abduce(([1, 1], None, 20), max_address_num = 2, require_more_address = 0) + res = kb.get_candidates_GKB(18) + print(res) + res = kb.get_candidates_GKB(16) print(res) print() - kb = add_prolog_KB() - abd = AbducerBase(kb, 'hamming') - res = abd.abduce(([1, 1], None, 17), max_address_num = 2, require_more_address = 0) - print(res) - res = abd.abduce(([1, 1], None, 17), max_address_num = 1, require_more_address = 0) - print(res) - res = abd.abduce(([1, 1], None, 20), max_address_num = 2, require_more_address = 0) - print(res) + # Without ground KB + kb = add_KB() + print('len(kb):', len(kb)) print() - kb = hwf_KB(len_list = [1, 3, 5]) - abd = AbducerBase(kb, 'hamming') - res = abd.abduce((['5', '+', '2'], None, 3), max_address_num = 2, require_more_address = 0) + # Prolog + kb = add_prolog_KB() + print(kb.logic_forward([3, 4])) + res = kb.get_candidates_prolog(16) print(res) - res = abd.abduce((['5', '+', '2'], None, 64), max_address_num = 3, require_more_address = 0) + + start = time.time() + kb = hwf_KB(GKB_flag = True, len_list = [1, 3, 5]) + print(time.time() - start) + print('len(kb):', len(kb)) + res = kb.get_candidates_GKB(2, length = 1) print(res) - res = abd.abduce((['5', '+', '2'], None, 1.67), max_address_num = 3, require_more_address = 0) + res = kb.get_candidates_GKB(1, length = 3) print(res) - res = abd.abduce((['5', '8', '8', '8', '8'], None, 3.17), max_address_num = 5, require_more_address = 3) + res = kb.get_candidates_GKB(3.67, length = 5) print(res) print() + + # X = ["1+1", "0+1", "1+0", "2+0", "1+0+1"] + # Y = [2, 1, 1, 2, 2] + # kb = ClsKB(X, Y) + # print('len(kb):', len(kb)) + # res = kb.get_candidates(2, 5) + # print(res) + # res = kb.get_candidates(2, 3) + # print(res) + # res = kb.get_candidates(None) + # print(res) + # print() + + # X = ["1+1", "0+1", "1+0", "2+0", "1+0.5", "0.75+0.75"] + # Y = [2, 1, 1, 2, 1.5, 1.5] + # kb = RegKB(X, Y) + # print('len(kb):', len(kb)) + # res = kb.get_candidates(1.6) + # print(res) + # res = kb.get_candidates(1.6, length = 9) + # print(res) + # res = kb.get_candidates(None) + # print(res) + From 15e4427702179edb463e65fcedabd00e484986cb Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 24 Nov 2022 17:42:43 +0800 Subject: [PATCH 082/601] Update abducer_base.py --- abducer/abducer_base.py | 102 ++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 68 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 63a3c73..f26b363 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -14,7 +14,7 @@ import sys sys.path.append("..") import abc -from abducer.kb import add_KB, hwf_KB +from abducer.kb import add_KB, hwf_KB, add_prolog_KB import numpy as np from itertools import product, combinations @@ -67,35 +67,31 @@ class AbducerBase(abc.ABC): min_address_num = np.min(cost_list) idxs = np.where(cost_list == min_address_num)[0] return [candidates[idx] for idx in idxs][0] + + def filter_all_candidates(self, pred_res, all_candidates, max_address_num, require_more_address): + if len(all_candidates) == 0: + candidates = [] + min_address_num = 0 + address_num = 0 + else: + cost_list = self.hamming_dist(pred_res, all_candidates) + min_address_num = np.min(cost_list) + address_num = min(max_address_num, min_address_num + require_more_address) + idxs = np.where(cost_list <= address_num)[0] + candidates = [all_candidates[idx] for idx in idxs] + return candidates, min_address_num, address_num def abduce(self, data, max_address_num = -1, require_more_address = 0): pred_res, pred_res_prob, ans = data - if max_address_num == -1: - max_address_num = len(pred_res) if self.cache and (tuple(pred_res), ans) in self.cache_min_address_num: address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), ans)] + require_more_address) if (tuple(pred_res), ans, address_num) in self.cache_candidates: - # print('cached') candidates = self.cache_candidates[(tuple(pred_res), ans, address_num)] candidate = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) return candidate - - if self.kb.GKB_flag: - all_candidates = self.kb.get_candidates(ans, len(pred_res)) - if len(all_candidates) == 0: - candidates = [] - min_address_num = 0 - address_num = 0 - else: - cost_list = self.hamming_dist(pred_res, all_candidates) - min_address_num = np.min(cost_list) - address_num = min(max_address_num, min_address_num + require_more_address) - idxs = np.where(cost_list <= address_num)[0] - candidates = [all_candidates[idx] for idx in idxs] - - else: - candidates, min_address_num, address_num = self.get_abduce_candidates(pred_res, ans, max_address_num, require_more_address) + + candidates, min_address_num, address_num = self.kb.abduce_candidates(pred_res, ans, max_address_num, require_more_address) if self.cache: self.cache_min_address_num[(tuple(pred_res), ans)] = min_address_num @@ -104,47 +100,6 @@ class AbducerBase(abc.ABC): candidate = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) return candidate - def address(self, address_num, pred_res, key): - new_candidates = [] - all_address_candidate = list(product(self.kb.pseudo_label_list, repeat = address_num)) - address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) - for address_idx in address_idx_list: - for c in all_address_candidate: - address_list = [pred_res[i] for i in address_idx] - if(sum([address_list[i] == c[i] for i in range(address_num)]) == 0): - candidate = pred_res.copy() - for i, idx in enumerate(address_idx): - candidate[idx] = c[i] - if self.kb.logic_forward(candidate) == key: - new_candidates.append(candidate) - return new_candidates - - def get_abduce_candidates(self, pred_res, key, max_address_num, require_more_address): - candidates = [] - print(pred_res) - for address_num in range(len(pred_res) + 1): - if address_num == 0: - if abs(self.kb.logic_forward(pred_res) - key) <= 1e-3: - candidates.append(pred_res) - else: - new_candidates = self.address(address_num, pred_res, key) - candidates += new_candidates - - if len(candidates) > 0: - min_address_num = address_num - break - - if address_num >= max_address_num: - return [], 0, 0 - - for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): - if address_num > max_address_num: - return candidates, min_address_num, address_num - 1 - new_candidates = self.address(address_num, pred_res, key) - candidates += new_candidates - - return candidates, min_address_num, address_num - def batch_abduce(self, Z, Y, max_address_num = -1, require_more_address = 0): return [ @@ -154,21 +109,30 @@ class AbducerBase(abc.ABC): def __call__(self, Z, Y, max_address_num = -1, require_more_address = 0): return self.batch_abduce(Z, Y, max_address_num, require_more_address) - - + if __name__ == '__main__': kb = add_KB(GKB_flag = True) abd = AbducerBase(kb, 'hamming') - res = abd.abduce(([1, 1], None, 4), max_address_num = 2, require_more_address = 0) + res = abd.abduce(([1, 1], None, 17), max_address_num = 2, require_more_address = 0) print(res) - res = abd.abduce(([1, 1], None, 4), max_address_num = 2, require_more_address = 1) + res = abd.abduce(([1, 1], None, 17), max_address_num = 1, require_more_address = 0) print(res) - res = abd.abduce(([1, 1], None, 5), max_address_num = 2, require_more_address = 1) + res = abd.abduce(([1, 1], None, 20), max_address_num = 2, require_more_address = 0) print(res) print() - kb = hwf_KB() + kb = add_prolog_KB() + abd = AbducerBase(kb, 'hamming') + res = abd.abduce(([1, 1], None, 17), max_address_num = 2, require_more_address = 0) + print(res) + res = abd.abduce(([1, 1], None, 17), max_address_num = 1, require_more_address = 0) + print(res) + res = abd.abduce(([1, 1], None, 20), max_address_num = 2, require_more_address = 0) + print(res) + print() + + kb = hwf_KB(len_list = [1, 3, 5]) abd = AbducerBase(kb, 'hamming') res = abd.abduce((['5', '+', '2'], None, 3), max_address_num = 2, require_more_address = 0) print(res) @@ -176,6 +140,8 @@ if __name__ == '__main__': print(res) res = abd.abduce((['5', '+', '2'], None, 1.67), max_address_num = 3, require_more_address = 0) print(res) - res = abd.abduce((['5', '+', '3'], None, 0.33), max_address_num = 3, require_more_address = 3) + res = abd.abduce((['5', '8', '8', '8', '8'], None, 3.17), max_address_num = 5, require_more_address = 3) print(res) print() + + From 2c2f38d60b445ca830771d3e5a0eba080bd1ecd8 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 24 Nov 2022 17:48:52 +0800 Subject: [PATCH 083/601] Update framework.py --- framework.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework.py b/framework.py index ed013b7..2a1fdad 100644 --- a/framework.py +++ b/framework.py @@ -68,7 +68,7 @@ def train(model, abducer, train_data, test_data, epochs = 50, sample_num = -1, v # Set default parameters if sample_num == -1: - sample_num = len(X) + sample_num = len(train_X) if verbose < 1: verbose = epochs From cdb8bc2067b8c3cce5f24a587d341bb002e6e56f Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 24 Nov 2022 21:42:12 +0800 Subject: [PATCH 084/601] Update kb.py --- abducer/kb.py | 170 +++++++++++++++++++------------------------------- 1 file changed, 63 insertions(+), 107 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 2600f8b..63c4959 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -32,23 +32,32 @@ class KBBase(ABC): def abduce_candidates(self): pass - def filter_all_candidates(self, pred_res, all_candidates, max_address_num, require_more_address): - if len(all_candidates) == 0: - candidates = [] - min_address_num = 0 - address_num = 0 - else: - cost_list = self.hamming_dist(pred_res, all_candidates) - min_address_num = np.min(cost_list) - address_num = min(max_address_num, min_address_num + require_more_address) - idxs = np.where(cost_list <= address_num)[0] - candidates = [all_candidates[idx] for idx in idxs] + + def abduction(self, pred_res, key, max_address_num, require_more_address): + candidates = [] + for address_num in range(len(pred_res) + 1): + if address_num == 0: + if abs(self.logic_forward(pred_res) - key) <= 1e-3: + candidates.append(pred_res) + else: + new_candidates = self.address(address_num, pred_res, key) + candidates += new_candidates + + if len(candidates) > 0: + min_address_num = address_num + break + + if address_num >= max_address_num: + return [], 0, 0 + + for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): + if address_num > max_address_num: + return candidates, min_address_num, address_num - 1 + new_candidates = self.address(address_num, pred_res, key) + candidates += new_candidates + return candidates, min_address_num, address_num - def hamming_dist(self, A, B): - B = np.array(B) - A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) - return np.sum(A != B, axis = 1) def __len__(self): pass @@ -90,66 +99,38 @@ class ClsKB(KBBase): pass def abduce_candidates(self, pred_res, key, max_address_num = -1, require_more_address = 0): - if max_address_num == -1: - max_address_num = len(pred_res) if self.GKB_flag: - all_candidates = self.get_candidates_GKB(key, len(pred_res)) - return self.filter_all_candidates(pred_res, all_candidates, max_address_num, require_more_address) + return self.abduce_from_GKB(pred_res, key, max_address_num, require_more_address) else: return self.abduction(pred_res, key, max_address_num, require_more_address) - def get_candidates_GKB(self, key, length = None): - if self.base == {}: + def abduce_from_GKB(self, pred_res, key, max_address_num, require_more_address): + if self.base == {} or len(pred_res) not in self.len_list: return [] - if key is None: - return self.get_all_candidates() + all_candidates = self.base[len(pred_res)][key] - if length is None: - length = list(self.base.keys()) - elif type(length) is int and length not in self.len_list: - return [] + if len(all_candidates) == 0: + candidates = [] + min_address_num = 0 + address_num = 0 else: - length = [length] - - return sum([self.base[l][key] for l in length], []) + cost_list = self.hamming_dist(pred_res, all_candidates) + min_address_num = np.min(cost_list) + address_num = min(max_address_num, min_address_num + require_more_address) + idxs = np.where(cost_list <= address_num)[0] + candidates = [all_candidates[idx] for idx in idxs] + + return candidates, min_address_num, address_num - def get_all_candidates(self): - if self.base == {}: - return [] - else: - return sum([sum(v.values(), []) for v in self.base.values()], []) + def hamming_dist(self, A, B): + B = np.array(B) + A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) + return np.sum(A != B, axis = 1) - - - - - def abduction(self, pred_res, key, max_address_num, require_more_address): - candidates = [] - for address_num in range(len(pred_res) + 1): - if address_num == 0: - if abs(self.logic_forward(pred_res) - key) <= 1e-3: - candidates.append(pred_res) - else: - new_candidates = self.address(address_num, pred_res, key) - candidates += new_candidates - - if len(candidates) > 0: - min_address_num = address_num - break - - if address_num >= max_address_num: - return [], 0, 0 - - for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): - if address_num > max_address_num: - return candidates, min_address_num, address_num - 1 - new_candidates = self.address(address_num, pred_res, key) - candidates += new_candidates - return candidates, min_address_num, address_num def address(self, address_num, pred_res, key): new_candidates = [] @@ -214,9 +195,6 @@ class hwf_KB(ClsKB): return round(eval(''.join(formula)), 2) - - - class prolog_KB(KBBase): def __init__(self, pseudo_label_list): super().__init__() @@ -224,16 +202,29 @@ class prolog_KB(KBBase): self.prolog = pyswip.Prolog() for i in self.pseudo_label_list: self.prolog.assertz("pseudo_label(%s)" % i) - self.prolog_flag = True def logic_forward(self): pass - def abduce_candidates(self, pred_res, key, max_address_num = -1, require_more_address = 0): - if max_address_num == -1: - max_address_num = len(pred_res) - all_candidates = self.get_candidates_prolog(key) - return self.filter_all_candidates(pred_res, all_candidates, max_address_num, require_more_address) + def abduce_candidates(self, pred_res, key, max_address_num, require_more_address): + return self.abduction(pred_res, key, max_address_num, require_more_address) + + def address(self, address_num, pred_res, key): + new_candidates = [] + address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) + for address_idx in address_idx_list: + query_string = "addition(" + for idx, i in enumerate(pred_res): + tmp = 'Z' + str(idx) + ',' if idx in address_idx else str(i) + ',' + query_string += tmp + query_string += "%s)." + abduce_c = [list(z.values()) for z in list(self.prolog.query(query_string % key))] + for c in abduce_c: + candidate = pred_res.copy() + for i, idx in enumerate(address_idx): + candidate[idx] = c[i] + new_candidates.append(candidate) + return new_candidates class add_prolog_KB(prolog_KB): @@ -301,42 +292,7 @@ class RegKB(KBBase): import time if __name__ == "__main__": - # With ground KB - kb = add_KB(GKB_flag = True) - print('len(kb):', len(kb)) - res = kb.get_candidates_GKB(0) - print(res) - res = kb.get_candidates_GKB(18) - print(res) - res = kb.get_candidates_GKB(18) - print(res) - res = kb.get_candidates_GKB(16) - print(res) - print() - - # Without ground KB - kb = add_KB() - print('len(kb):', len(kb)) - print() - - # Prolog - kb = add_prolog_KB() - print(kb.logic_forward([3, 4])) - res = kb.get_candidates_prolog(16) - print(res) - - start = time.time() - kb = hwf_KB(GKB_flag = True, len_list = [1, 3, 5]) - print(time.time() - start) - print('len(kb):', len(kb)) - res = kb.get_candidates_GKB(2, length = 1) - print(res) - res = kb.get_candidates_GKB(1, length = 3) - print(res) - res = kb.get_candidates_GKB(3.67, length = 5) - print(res) - print() - + pass # X = ["1+1", "0+1", "1+0", "2+0", "1+0+1"] From 20146ee8dd710dbf475d2a9250b44394d92a0436 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 24 Nov 2022 21:42:27 +0800 Subject: [PATCH 085/601] Update abducer_base.py --- abducer/abducer_base.py | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index f26b363..93810c1 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -17,7 +17,6 @@ import abc from abducer.kb import add_KB, hwf_KB, add_prolog_KB import numpy as np -from itertools import product, combinations import time class AbducerBase(abc.ABC): @@ -26,7 +25,7 @@ class AbducerBase(abc.ABC): assert(dist_func == 'hamming' or dist_func == 'confidence') self.dist_func = dist_func self.cache = cache - + if self.cache: self.cache_min_address_num = {} self.cache_candidates = {} @@ -83,21 +82,23 @@ class AbducerBase(abc.ABC): def abduce(self, data, max_address_num = -1, require_more_address = 0): pred_res, pred_res_prob, ans = data + if max_address_num == -1: + max_address_num = len(pred_res) if self.cache and (tuple(pred_res), ans) in self.cache_min_address_num: address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), ans)] + require_more_address) if (tuple(pred_res), ans, address_num) in self.cache_candidates: candidates = self.cache_candidates[(tuple(pred_res), ans, address_num)] - candidate = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) - return candidate + return self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) candidates, min_address_num, address_num = self.kb.abduce_candidates(pred_res, ans, max_address_num, require_more_address) + if self.cache: self.cache_min_address_num[(tuple(pred_res), ans)] = min_address_num self.cache_candidates[(tuple(pred_res), ans, address_num)] = candidates - - candidate = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) + + candidate = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) return candidate @@ -112,23 +113,34 @@ class AbducerBase(abc.ABC): if __name__ == '__main__': + prob1 = [[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0],[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] + prob2 = [[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0],[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] + kb = add_KB(GKB_flag = True) - abd = AbducerBase(kb, 'hamming') - res = abd.abduce(([1, 1], None, 17), max_address_num = 2, require_more_address = 0) + abd = AbducerBase(kb, 'confidence') + res = abd.abduce(([1, 1], prob1, 8), max_address_num = 2, require_more_address = 0) + print(res) + res = abd.abduce(([1, 1], prob2, 8), max_address_num = 2, require_more_address = 0) + print(res) + res = abd.abduce(([1, 1], prob1, 17), max_address_num = 2, require_more_address = 0) print(res) - res = abd.abduce(([1, 1], None, 17), max_address_num = 1, require_more_address = 0) + res = abd.abduce(([1, 1], prob1, 17), max_address_num = 1, require_more_address = 0) print(res) - res = abd.abduce(([1, 1], None, 20), max_address_num = 2, require_more_address = 0) + res = abd.abduce(([1, 1], prob1, 20), max_address_num = 2, require_more_address = 0) print(res) print() kb = add_prolog_KB() - abd = AbducerBase(kb, 'hamming') - res = abd.abduce(([1, 1], None, 17), max_address_num = 2, require_more_address = 0) + abd = AbducerBase(kb, 'confidence') + res = abd.abduce(([1, 1], prob1, 8), max_address_num = 2, require_more_address = 0) + print(res) + res = abd.abduce(([1, 1], prob2, 8), max_address_num = 2, require_more_address = 0) + print(res) + res = abd.abduce(([1, 1], prob1, 17), max_address_num = 2, require_more_address = 0) print(res) - res = abd.abduce(([1, 1], None, 17), max_address_num = 1, require_more_address = 0) + res = abd.abduce(([1, 1], prob1, 17), max_address_num = 1, require_more_address = 0) print(res) - res = abd.abduce(([1, 1], None, 20), max_address_num = 2, require_more_address = 0) + res = abd.abduce(([1, 1], prob1, 20), max_address_num = 2, require_more_address = 0) print(res) print() From 880b2a1800dc9f13ded22cc18395a317dcb5cad5 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 24 Nov 2022 21:44:12 +0800 Subject: [PATCH 086/601] Update kb.py --- abducer/kb.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 63c4959..78ebb10 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -234,9 +234,6 @@ class add_prolog_KB(prolog_KB): def logic_forward(self, nums): return list(self.prolog.query("addition(%s, %s, Res)." %(nums[0], nums[1])))[0]['Res'] - - def get_candidates_prolog(self, key): - return [(z['Z1'], z['Z2']) for z in list(self.prolog.query("addition(Z1, Z2, %s)." % key))] class RegKB(KBBase): From 986e38b3a24072a510f5c56ee3773030f841a846 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 25 Nov 2022 09:54:04 +0800 Subject: [PATCH 087/601] Update kb.py --- abducer/kb.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 78ebb10..2415d6f 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -213,11 +213,7 @@ class prolog_KB(KBBase): new_candidates = [] address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) for address_idx in address_idx_list: - query_string = "addition(" - for idx, i in enumerate(pred_res): - tmp = 'Z' + str(idx) + ',' if idx in address_idx else str(i) + ',' - query_string += tmp - query_string += "%s)." + query_string = self.get_query_string(pred_res, address_idx) abduce_c = [list(z.values()) for z in list(self.prolog.query(query_string % key))] for c in abduce_c: candidate = pred_res.copy() @@ -234,6 +230,15 @@ class add_prolog_KB(prolog_KB): def logic_forward(self, nums): return list(self.prolog.query("addition(%s, %s, Res)." %(nums[0], nums[1])))[0]['Res'] + + def get_query_string(self, pred_res, address_idx): + query_string = "addition(" + for idx, i in enumerate(pred_res): + tmp = 'Z' + str(idx) + ',' if idx in address_idx else str(i) + ',' + query_string += tmp + query_string += "%s)." + return query_string + class RegKB(KBBase): From c6cd213dc8f9b24585970e244544a1da6b140073 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 25 Nov 2022 12:26:50 +0800 Subject: [PATCH 088/601] Update kb.py --- abducer/kb.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 2415d6f..0fdfb04 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -132,18 +132,17 @@ class ClsKB(KBBase): - def address(self, address_num, pred_res, key): + def address(self, address_num, pred_res, key): new_candidates = [] all_address_candidate = self.all_address_candidate_dict[address_num] address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) for address_idx in address_idx_list: for c in all_address_candidate: - address_list = [pred_res[i] for i in address_idx] - if(sum([address_list[i] == c[i] for i in range(address_num)]) == 0): - candidate = pred_res.copy() - for i, idx in enumerate(address_idx): - candidate[idx] = c[i] - if self.logic_forward(candidate) == key: + candidate = pred_res.copy() + for i, idx in enumerate(address_idx): + candidate[idx] = c[i] + if self.logic_forward(candidate) == key: + if(sum(pred_res[idx] != candidate[idx] for idx in range(len(pred_res))) == address_num): new_candidates.append(candidate) return new_candidates @@ -219,7 +218,8 @@ class prolog_KB(KBBase): candidate = pred_res.copy() for i, idx in enumerate(address_idx): candidate[idx] = c[i] - new_candidates.append(candidate) + if(sum(pred_res[idx] != candidate[idx] for idx in range(len(pred_res))) == address_num): + new_candidates.append(candidate) return new_candidates From c74e7c4b9f240c761cfc964ecc5579cb0a2da771 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 25 Nov 2022 12:32:05 +0800 Subject: [PATCH 089/601] Update kb.py --- abducer/kb.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 0fdfb04..9ff7652 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -142,7 +142,7 @@ class ClsKB(KBBase): for i, idx in enumerate(address_idx): candidate[idx] = c[i] if self.logic_forward(candidate) == key: - if(sum(pred_res[idx] != candidate[idx] for idx in range(len(pred_res))) == address_num): + if sum(pred_res[idx] != candidate[idx] for idx in range(len(pred_res))) == address_num: new_candidates.append(candidate) return new_candidates @@ -218,7 +218,7 @@ class prolog_KB(KBBase): candidate = pred_res.copy() for i, idx in enumerate(address_idx): candidate[idx] = c[i] - if(sum(pred_res[idx] != candidate[idx] for idx in range(len(pred_res))) == address_num): + if sum(pred_res[idx] != candidate[idx] for idx in range(len(pred_res))) == address_num: new_candidates.append(candidate) return new_candidates From 3b8f77e4ff91aa52390a7853d90adcb3cde14981 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 5 Dec 2022 16:33:36 +0800 Subject: [PATCH 090/601] Add zoopt option --- abducer/kb.py | 103 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 34 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 9ff7652..7ca8a25 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -20,6 +20,7 @@ from itertools import product, combinations import pyswip + class KBBase(ABC): def __init__(self): pass @@ -31,10 +32,20 @@ class KBBase(ABC): @abstractmethod def abduce_candidates(self): pass - + + + def address(self, address_num, pred_res, key): + new_candidates = [] + address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) + + for address_idx in address_idx_list: + candidates = self.address_by_idx(pred_res, key, address_idx) + new_candidates += candidates + return new_candidates def abduction(self, pred_res, key, max_address_num, require_more_address): candidates = [] + for address_num in range(len(pred_res) + 1): if address_num == 0: if abs(self.logic_forward(pred_res) - key) <= 1e-3: @@ -106,6 +117,11 @@ class ClsKB(KBBase): + def hamming_dist(self, A, B): + B = np.array(B) + A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) + return np.sum(A != B, axis = 1) + def abduce_from_GKB(self, pred_res, key, max_address_num, require_more_address): if self.base == {} or len(pred_res) not in self.len_list: return [] @@ -124,28 +140,18 @@ class ClsKB(KBBase): candidates = [all_candidates[idx] for idx in idxs] return candidates, min_address_num, address_num - - def hamming_dist(self, A, B): - B = np.array(B) - A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) - return np.sum(A != B, axis = 1) - - def address(self, address_num, pred_res, key): - new_candidates = [] - all_address_candidate = self.all_address_candidate_dict[address_num] - address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) - for address_idx in address_idx_list: - for c in all_address_candidate: - candidate = pred_res.copy() - for i, idx in enumerate(address_idx): - candidate[idx] = c[i] - if self.logic_forward(candidate) == key: - if sum(pred_res[idx] != candidate[idx] for idx in range(len(pred_res))) == address_num: - new_candidates.append(candidate) - return new_candidates - + def address_by_idx(self, pred_res, key, address_idx): + candidates = [] + abduce_c = self.all_address_candidate_dict[len(address_idx)] + for c in abduce_c: + candidate = pred_res.copy() + for i, idx in enumerate(address_idx): + candidate[idx] = c[i] + if self.logic_forward(candidate) == key: + candidates.append(candidate) + return candidates def _dict_len(self, dic): @@ -208,19 +214,32 @@ class prolog_KB(KBBase): def abduce_candidates(self, pred_res, key, max_address_num, require_more_address): return self.abduction(pred_res, key, max_address_num, require_more_address) - def address(self, address_num, pred_res, key): - new_candidates = [] - address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) - for address_idx in address_idx_list: - query_string = self.get_query_string(pred_res, address_idx) - abduce_c = [list(z.values()) for z in list(self.prolog.query(query_string % key))] - for c in abduce_c: - candidate = pred_res.copy() - for i, idx in enumerate(address_idx): - candidate[idx] = c[i] - if sum(pred_res[idx] != candidate[idx] for idx in range(len(pred_res))) == address_num: - new_candidates.append(candidate) - return new_candidates + + + def address_by_idx(self, pred_res, key, address_idx, verbose=True): + candidates = [] + query_string = self.get_query_string(pred_res, address_idx) + abduce_c = [list(z.values()) for z in list(self.prolog.query(query_string % key))] + for c in abduce_c: + candidate = pred_res.copy() + for i, idx in enumerate(address_idx): + candidate[idx] = c[i] + candidates.append(candidate) + return candidates + + def address_by_idx2(self, pred_res, key, address_idx): + candidates = [] + query_string = self.get_query_string(pred_res, address_idx) + abduce_c = [list(z.values()) for z in list(self.prolog.query(query_string % key))] + # print('abduce_c:', abduce_c) + for c in abduce_c: + candidate = pred_res.copy() + for i, idx in enumerate(address_idx): + candidate[idx] = c[i] + candidates.append(candidate) + return candidates + + class add_prolog_KB(prolog_KB): @@ -240,6 +259,22 @@ class add_prolog_KB(prolog_KB): return query_string +class hed_prolog_KB(prolog_KB): + def __init__(self, pseudo_label_list = list(range(10))): + super().__init__(pseudo_label_list) + self.prolog.assertz("addition(Z1, Z2, Res) :- pseudo_label(Z1), pseudo_label(Z2), Res is Z1+Z2") + + def logic_forward(self, nums): + return list(self.prolog.query("addition(%s, %s, Res)." %(nums[0], nums[1])))[0]['Res'] + + def get_query_string(self, pred_res, address_idx): + query_string = "addition(" + for idx, i in enumerate(pred_res): + tmp = 'Z' + str(idx) + ',' if idx in address_idx else str(i) + ',' + query_string += tmp + query_string += "%s)." + return query_string + class RegKB(KBBase): def __init__(self, GKB_flag = False, X = None, Y = None): From 4a217b71b7adc13abc8a3318c4c6df88dc6d2448 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 5 Dec 2022 16:33:53 +0800 Subject: [PATCH 091/601] Add zoopt option --- abducer/abducer_base.py | 95 ++++++++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 29 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 93810c1..ce4601b 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -16,19 +16,22 @@ sys.path.append("..") import abc from abducer.kb import add_KB, hwf_KB, add_prolog_KB import numpy as np +from zoopt import Dimension, Objective, Parameter, Opt import time class AbducerBase(abc.ABC): - def __init__(self, kb, dist_func = 'confidence', cache = True): + def __init__(self, kb, dist_func = 'confidence', zoopt = False, cache = True): self.kb = kb assert(dist_func == 'hamming' or dist_func == 'confidence') self.dist_func = dist_func self.cache = cache - + self.zoopt = zoopt + if self.cache: self.cache_min_address_num = {} self.cache_candidates = {} + def hamming_dist(self, A, B): B = np.array(B) @@ -66,38 +69,58 @@ class AbducerBase(abc.ABC): min_address_num = np.min(cost_list) idxs = np.where(cost_list == min_address_num)[0] return [candidates[idx] for idx in idxs][0] + + + + def zoopt_address_score(self, pred_res, key, address_idx): + candidates = self.kb.address_by_idx2(pred_res, key, address_idx) + return 0 if len(candidates) > 0 else 1 - def filter_all_candidates(self, pred_res, all_candidates, max_address_num, require_more_address): - if len(all_candidates) == 0: - candidates = [] - min_address_num = 0 - address_num = 0 - else: - cost_list = self.hamming_dist(pred_res, all_candidates) - min_address_num = np.min(cost_list) - address_num = min(max_address_num, min_address_num + require_more_address) - idxs = np.where(cost_list <= address_num)[0] - candidates = [all_candidates[idx] for idx in idxs] - return candidates, min_address_num, address_num + def constraint_address_num(self, solution, max_address_num): + x = solution.get_x() + return max_address_num - x.sum() + + def zoopt_get_address_idx(self, pred_res, key, max_address_num): + dimension = Dimension(size=len(pred_res), + regs=[[0, 1]] * len(pred_res), + tys=[False] * len(pred_res)) + objective = Objective(lambda sol: self.zoopt_address_score(pred_res, key, [idx for idx, i in enumerate(sol.get_x()) if i != 0]), + dim=dimension, + constraint=lambda sol: self.constraint_address_num(sol, max_address_num)) + parameter = Parameter(budget=100 * dimension.get_size(), autoset=True) + solution = Opt.min(objective, parameter).get_x() + + address_idx = [idx for idx, i in enumerate(solution) if i != 0] + address_num = solution.sum() + + return address_idx, address_num + + + def abduce(self, data, max_address_num = -1, require_more_address = 0): - pred_res, pred_res_prob, ans = data + pred_res, pred_res_prob, key = data if max_address_num == -1: max_address_num = len(pred_res) - - if self.cache and (tuple(pred_res), ans) in self.cache_min_address_num: - address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), ans)] + require_more_address) - if (tuple(pred_res), ans, address_num) in self.cache_candidates: - candidates = self.cache_candidates[(tuple(pred_res), ans, address_num)] + + if self.cache and (tuple(pred_res), key) in self.cache_min_address_num: + address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), key)] + require_more_address) + if (tuple(pred_res), key, address_num) in self.cache_candidates: + candidates = self.cache_candidates[(tuple(pred_res), key, address_num)] return self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) - candidates, min_address_num, address_num = self.kb.abduce_candidates(pred_res, ans, max_address_num, require_more_address) - - + if self.zoopt: + address_idx, address_num = self.zoopt_get_address_idx(pred_res, key, max_address_num) + candidates = self.kb.address_by_idx(pred_res, key, address_idx) + min_address_num = address_num + else: + candidates, min_address_num, address_num = self.kb.abduce_candidates(pred_res, key, max_address_num, require_more_address) + + if self.cache: - self.cache_min_address_num[(tuple(pred_res), ans)] = min_address_num - self.cache_candidates[(tuple(pred_res), ans, address_num)] = candidates - + self.cache_min_address_num[(tuple(pred_res), key)] = min_address_num + self.cache_candidates[(tuple(pred_res), key, address_num)] = candidates + candidate = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) return candidate @@ -113,8 +136,8 @@ class AbducerBase(abc.ABC): if __name__ == '__main__': - prob1 = [[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0],[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] - prob2 = [[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0],[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] + prob1 = [[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] + prob2 = [[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] kb = add_KB(GKB_flag = True) abd = AbducerBase(kb, 'confidence') @@ -144,6 +167,20 @@ if __name__ == '__main__': print(res) print() + kb = add_prolog_KB() + abd = AbducerBase(kb, 'confidence', zoopt = True) + res = abd.abduce(([1, 1], prob1, 8), max_address_num = 2, require_more_address = 0) + print(res) + res = abd.abduce(([1, 1], prob2, 8), max_address_num = 2, require_more_address = 0) + print(res) + res = abd.abduce(([1, 1], prob1, 17), max_address_num = 2, require_more_address = 0) + print(res) + res = abd.abduce(([1, 1], prob1, 17), max_address_num = 1, require_more_address = 0) + print(res) + res = abd.abduce(([1, 1], prob1, 20), max_address_num = 2, require_more_address = 0) + print(res) + print() + kb = hwf_KB(len_list = [1, 3, 5]) abd = AbducerBase(kb, 'hamming') res = abd.abduce((['5', '+', '2'], None, 3), max_address_num = 2, require_more_address = 0) @@ -156,4 +193,4 @@ if __name__ == '__main__': print(res) print() - + From 6d247b41fb8c667885ee7069b0c4380aa2e7392b Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 5 Dec 2022 16:35:11 +0800 Subject: [PATCH 092/601] Update abducer_base.py --- abducer/abducer_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index ce4601b..0a7f6cb 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -73,7 +73,7 @@ class AbducerBase(abc.ABC): def zoopt_address_score(self, pred_res, key, address_idx): - candidates = self.kb.address_by_idx2(pred_res, key, address_idx) + candidates = self.kb.address_by_idx(pred_res, key, address_idx) return 0 if len(candidates) > 0 else 1 def constraint_address_num(self, solution, max_address_num): From 19c6c346b86e2b073d3e2424f42650ce3a54ea12 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 5 Dec 2022 16:35:45 +0800 Subject: [PATCH 093/601] Add zoopt option --- abducer/kb.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 7ca8a25..4a0c9a0 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -226,20 +226,7 @@ class prolog_KB(KBBase): candidate[idx] = c[i] candidates.append(candidate) return candidates - - def address_by_idx2(self, pred_res, key, address_idx): - candidates = [] - query_string = self.get_query_string(pred_res, address_idx) - abduce_c = [list(z.values()) for z in list(self.prolog.query(query_string % key))] - # print('abduce_c:', abduce_c) - for c in abduce_c: - candidate = pred_res.copy() - for i, idx in enumerate(address_idx): - candidate[idx] = c[i] - candidates.append(candidate) - return candidates - - + class add_prolog_KB(prolog_KB): From 279cb7a703aac1278b6aecb8c0b23eb35d2f11a2 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 5 Dec 2022 16:36:08 +0800 Subject: [PATCH 094/601] Add zoopt option --- abducer/abducer_base.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 0a7f6cb..d0baf1f 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -51,8 +51,7 @@ class AbducerBase(abc.ABC): cols = np.array(range(len(B[0]))) cols = np.expand_dims(cols, axis = 0).repeat(axis = 0, repeats = len(B)) return 1 - np.prod(A[rows, cols, B], axis = 1) - - + def get_cost_list(self, pred_res, pred_res_prob, candidates): if self.dist_func == 'hamming': return self.hamming_dist(pred_res, candidates) From 0f1307dd10636e8f48b50c018d1d652acec72435 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 5 Dec 2022 16:40:55 +0800 Subject: [PATCH 095/601] Add zoopt option --- abducer/kb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abducer/kb.py b/abducer/kb.py index 4a0c9a0..db2bf6f 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -89,7 +89,7 @@ class ClsKB(KBBase): self.base.setdefault(len(x), defaultdict(list))[y].append(x) else: self.all_address_candidate_dict = {} - for address_num in range(1, max(self.len_list) + 1): + for address_num in range(max(self.len_list) + 1): self.all_address_candidate_dict[address_num] = list(product(self.pseudo_label_list, repeat = address_num)) def get_GKB(self, pseudo_label_list, len_list): From c4ab9843d307fe4dd2d8279e941794b5d9f348ac Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 5 Dec 2022 16:52:17 +0800 Subject: [PATCH 096/601] Add zoopt option --- abducer/abducer_base.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index d0baf1f..e2072ec 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -106,21 +106,26 @@ class AbducerBase(abc.ABC): address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), key)] + require_more_address) if (tuple(pred_res), key, address_num) in self.cache_candidates: candidates = self.cache_candidates[(tuple(pred_res), key, address_num)] - return self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) + if self.zoopt: + return candidates[0] + else: + return self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) if self.zoopt: address_idx, address_num = self.zoopt_get_address_idx(pred_res, key, max_address_num) candidates = self.kb.address_by_idx(pred_res, key, address_idx) min_address_num = address_num + candidate = candidates[0] else: candidates, min_address_num, address_num = self.kb.abduce_candidates(pred_res, key, max_address_num, require_more_address) + candidate = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) if self.cache: self.cache_min_address_num[(tuple(pred_res), key)] = min_address_num self.cache_candidates[(tuple(pred_res), key, address_num)] = candidates - candidate = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) + return candidate @@ -138,7 +143,7 @@ if __name__ == '__main__': prob1 = [[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] prob2 = [[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] - kb = add_KB(GKB_flag = True) + kb = add_KB() abd = AbducerBase(kb, 'confidence') res = abd.abduce(([1, 1], prob1, 8), max_address_num = 2, require_more_address = 0) print(res) @@ -192,4 +197,3 @@ if __name__ == '__main__': print(res) print() - From 97daae2839fccc65be2c84b7481c22207eaa6d33 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:47:32 +0800 Subject: [PATCH 097/601] Update readme.md --- readme.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/readme.md b/readme.md index 1a9ebf1..e3726a9 100644 --- a/readme.md +++ b/readme.md @@ -24,10 +24,10 @@ They can only be used for academic purpose. For other purposes, please contact w ## To do list -- Improve speed and accuracy -- Add comparison with DeepProbLog, NGS,... (Accuracy and Speed) -- Add Inference/Abduction example with FOL engine (e.g., Prolog) -- Add zoopt optimization -- Rearrange structure and make it a python package -- Documents +- [ ] Improve speed and accuracy +- [ ] Add comparison with DeepProbLog, NGS,... (Accuracy and Speed) +- [x] Add Inference/Abduction example with FOL engine (e.g., Prolog) +- [x] Add zoopt optimization +- [ ] Rearrange structure and make it a python package +- [ ] Documents From c4c2f7e030ca5cd794facf2aa0e039a619e504e1 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 7 Dec 2022 12:51:45 +0800 Subject: [PATCH 098/601] Add kb and abducer for HED --- abducer/kb.py | 133 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 98 insertions(+), 35 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index db2bf6f..9ae8efd 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -22,7 +22,7 @@ import pyswip class KBBase(ABC): - def __init__(self): + def __init__(self, pseudo_label_list = None): pass @abstractmethod @@ -34,16 +34,16 @@ class KBBase(ABC): pass - def address(self, address_num, pred_res, key): + def address(self, address_num, pred_res, key, multiple_predictions = False): new_candidates = [] address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) for address_idx in address_idx_list: - candidates = self.address_by_idx(pred_res, key, address_idx) + candidates = self.address_by_idx(pred_res, key, address_idx, multiple_predictions) new_candidates += candidates return new_candidates - def abduction(self, pred_res, key, max_address_num, require_more_address): + def abduction(self, pred_res, key, max_address_num, require_more_address, multiple_predictions = False): candidates = [] for address_num in range(len(pred_res) + 1): @@ -51,7 +51,7 @@ class KBBase(ABC): if abs(self.logic_forward(pred_res) - key) <= 1e-3: candidates.append(pred_res) else: - new_candidates = self.address(address_num, pred_res, key) + new_candidates = self.address(address_num, pred_res, key, multiple_predictions) candidates += new_candidates if len(candidates) > 0: @@ -64,12 +64,30 @@ class KBBase(ABC): for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): if address_num > max_address_num: return candidates, min_address_num, address_num - 1 - new_candidates = self.address(address_num, pred_res, key) + new_candidates = self.address(address_num, pred_res, key, multiple_predictions) candidates += new_candidates return candidates, min_address_num, address_num + # for multiple predictions, modify from `learn_add.py` + def flatten(self, l): + return [item for sublist in l for item in sublist] + + # for multiple predictions, modify from `learn_add.py` + def reform_ids(self, flatten_pred_res, save_pred_res): + re = [] + i = 0 + for e in save_pred_res: + j = 0 + ids = [] + while j < len(e): + ids.append(flatten_pred_res[i + j]) + j += 1 + re.append(ids) + i = i + j + return re + def __len__(self): pass @@ -82,7 +100,6 @@ class ClsKB(KBBase): self.prolog_flag = False if GKB_flag: - # self.base = np.load('abducer/hwf.npy', allow_pickle=True).item() self.base = {} X, Y = self.get_GKB(self.pseudo_label_list, self.len_list) for x, y in zip(X, Y): @@ -109,11 +126,11 @@ class ClsKB(KBBase): def logic_forward(self): pass - def abduce_candidates(self, pred_res, key, max_address_num = -1, require_more_address = 0): + def abduce_candidates(self, pred_res, key, max_address_num = -1, require_more_address = 0, multiple_predictions = False): if self.GKB_flag: return self.abduce_from_GKB(pred_res, key, max_address_num, require_more_address) else: - return self.abduction(pred_res, key, max_address_num, require_more_address) + return self.abduction(pred_res, key, max_address_num, require_more_address, multiple_predictions) @@ -142,14 +159,23 @@ class ClsKB(KBBase): return candidates, min_address_num, address_num - def address_by_idx(self, pred_res, key, address_idx): + def address_by_idx(self, pred_res, key, address_idx, multiple_predictions = False): candidates = [] abduce_c = self.all_address_candidate_dict[len(address_idx)] + + if multiple_predictions: + save_pred_res = pred_res + pred_res = self.flatten(pred_res) + for c in abduce_c: candidate = pred_res.copy() for i, idx in enumerate(address_idx): candidate[idx] = c[i] - if self.logic_forward(candidate) == key: + + if multiple_predictions: + candidate = self.reform_ids(candidate, save_pred_res) + + if self.logic_forward(candidate) == key: candidates.append(candidate) return candidates @@ -176,7 +202,7 @@ class add_KB(ClsKB): def logic_forward(self, nums): return sum(nums) -class hwf_KB(ClsKB): +class HWF_KB(ClsKB): def __init__(self, GKB_flag = False, \ pseudo_label_list = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', 'times', 'div'], \ len_list = [1, 3, 5, 7]): @@ -205,62 +231,99 @@ class prolog_KB(KBBase): super().__init__() self.pseudo_label_list = pseudo_label_list self.prolog = pyswip.Prolog() - for i in self.pseudo_label_list: - self.prolog.assertz("pseudo_label(%s)" % i) + def logic_forward(self): pass - def abduce_candidates(self, pred_res, key, max_address_num, require_more_address): - return self.abduction(pred_res, key, max_address_num, require_more_address) + def abduce_candidates(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): + return self.abduction(pred_res, key, max_address_num, require_more_address, multiple_predictions) - def address_by_idx(self, pred_res, key, address_idx, verbose=True): + def address_by_idx(self, pred_res, key, address_idx, multiple_predictions = False): candidates = [] - query_string = self.get_query_string(pred_res, address_idx) - abduce_c = [list(z.values()) for z in list(self.prolog.query(query_string % key))] + + if not multiple_predictions: + query_string = self.get_query_string(pred_res, key, address_idx) + else: + query_string = self.get_query_string_need_flatten(pred_res, key, address_idx) + + if multiple_predictions: + save_pred_res = pred_res + pred_res = self.flatten(pred_res) + + abduce_c = [list(z.values()) for z in list(self.prolog.query(query_string))] for c in abduce_c: candidate = pred_res.copy() for i, idx in enumerate(address_idx): candidate[idx] = c[i] + + if multiple_predictions: + candidate = self.reform_ids(candidate, save_pred_res) + candidates.append(candidate) - return candidates - + return candidates class add_prolog_KB(prolog_KB): def __init__(self, pseudo_label_list = list(range(10))): super().__init__(pseudo_label_list) + for i in self.pseudo_label_list: + self.prolog.assertz("pseudo_label(%s)" % i) self.prolog.assertz("addition(Z1, Z2, Res) :- pseudo_label(Z1), pseudo_label(Z2), Res is Z1+Z2") def logic_forward(self, nums): return list(self.prolog.query("addition(%s, %s, Res)." %(nums[0], nums[1])))[0]['Res'] - def get_query_string(self, pred_res, address_idx): + def get_query_string(self, pred_res, key, address_idx): query_string = "addition(" for idx, i in enumerate(pred_res): tmp = 'Z' + str(idx) + ',' if idx in address_idx else str(i) + ',' query_string += tmp - query_string += "%s)." + query_string += "%s)." % key return query_string -class hed_prolog_KB(prolog_KB): - def __init__(self, pseudo_label_list = list(range(10))): +class HED_prolog_KB(prolog_KB): + def __init__(self, pseudo_label_list = [0, 1, '+', '=']): super().__init__(pseudo_label_list) - self.prolog.assertz("addition(Z1, Z2, Res) :- pseudo_label(Z1), pseudo_label(Z2), Res is Z1+Z2") + self.prolog.consult('../datasets/hed/learn_add.pl') - def logic_forward(self, nums): - return list(self.prolog.query("addition(%s, %s, Res)." %(nums[0], nums[1])))[0]['Res'] + # corresponding to `con_sol is not None` in `consistent_score_mapped` within `learn_add.py` + def logic_forward(self, exs): + return len(list(self.prolog.query("abduce_consistent_insts(%s)." % exs))) != 0 - def get_query_string(self, pred_res, address_idx): - query_string = "addition(" - for idx, i in enumerate(pred_res): - tmp = 'Z' + str(idx) + ',' if idx in address_idx else str(i) + ',' - query_string += tmp - query_string += "%s)." - return query_string + + def get_query_string_need_flatten(self, pred_res, key, address_idx): + # flatten + flatten_pred_res = self.flatten(pred_res) + # add variables for prolog + for idx in range(len(flatten_pred_res)): + if idx in address_idx: + flatten_pred_res[idx] = 'X' + str(idx) + # unflatten + new_pred_res = self.reform_ids(flatten_pred_res, pred_res) + + query_string = "abduce_consistent_insts(%s)." % new_pred_res + return query_string.replace("'", "").replace("+", "'+'").replace("=", "'='") + + + + def consist_rule(self, exs, rules): + rule_str = "%s" % rules + rule_str = rule_str.replace("'", "") + return len(list(self.prolog.query("consistent_inst_feature(%s, %s)." %(exs, rule_str)))) != 0 + + def abduce_rules(self, pred_res): + prolog_rules = list(self.prolog.query("consistent_inst_feature(%s, X)." % pred_res))[0]['X'] + rules = [] + for rule in prolog_rules: + rules.append(rule.value) + return rules + + # def consist_rules(self, pred_res, rules): + class RegKB(KBBase): From 2587ac2f7e4d64b2539c10d97ff04927970a0e26 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 7 Dec 2022 12:52:14 +0800 Subject: [PATCH 099/601] Add kb and abducer for HED --- abducer/abducer_base.py | 80 +++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 23 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index e2072ec..8fde5a1 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -14,19 +14,20 @@ import sys sys.path.append("..") import abc -from abducer.kb import add_KB, hwf_KB, add_prolog_KB +from abducer.kb import add_KB, HWF_KB, add_prolog_KB, HED_prolog_KB import numpy as np from zoopt import Dimension, Objective, Parameter, Opt import time class AbducerBase(abc.ABC): - def __init__(self, kb, dist_func = 'confidence', zoopt = False, cache = True): + def __init__(self, kb, dist_func = 'confidence', zoopt = False, multiple_predictions = False, cache = True): self.kb = kb assert(dist_func == 'hamming' or dist_func == 'confidence') self.dist_func = dist_func - self.cache = cache self.zoopt = zoopt + self.multiple_predictions = multiple_predictions + self.cache = cache if self.cache: self.cache_min_address_num = {} @@ -58,10 +59,10 @@ class AbducerBase(abc.ABC): elif self.dist_func == 'confidence': return self.confidence_dist(pred_res_prob, candidates) - def get_min_cost_candidate(self, pred_res, pred_res_prob, candidates): + def get_one_candidate(self, pred_res, pred_res_prob, candidates): if len(candidates) == 0: return [] - elif len(candidates) == 1: + elif len(candidates) == 1 or self.zoopt: return candidates[0] else: cost_list = self.get_cost_list(pred_res, pred_res_prob, candidates) @@ -71,8 +72,19 @@ class AbducerBase(abc.ABC): + + # for multiple_prediction + def flatten(self, l): + if self.multiple_predictions: + return [item for sublist in l for item in sublist] + else: + return l + + + + # for zoopt def zoopt_address_score(self, pred_res, key, address_idx): - candidates = self.kb.address_by_idx(pred_res, key, address_idx) + candidates = self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) return 0 if len(candidates) > 0 else 1 def constraint_address_num(self, solution, max_address_num): @@ -80,9 +92,9 @@ class AbducerBase(abc.ABC): return max_address_num - x.sum() def zoopt_get_address_idx(self, pred_res, key, max_address_num): - dimension = Dimension(size=len(pred_res), - regs=[[0, 1]] * len(pred_res), - tys=[False] * len(pred_res)) + dimension = Dimension(size=len(self.flatten(pred_res)), + regs=[[0, 1]] * len(self.flatten(pred_res)), + tys=[False] * len(self.flatten(pred_res))) objective = Objective(lambda sol: self.zoopt_address_score(pred_res, key, [idx for idx, i in enumerate(sol.get_x()) if i != 0]), dim=dimension, constraint=lambda sol: self.constraint_address_num(sol, max_address_num)) @@ -90,7 +102,7 @@ class AbducerBase(abc.ABC): solution = Opt.min(objective, parameter).get_x() address_idx = [idx for idx, i in enumerate(solution) if i != 0] - address_num = solution.sum() + address_num = int(solution.sum()) return address_idx, address_num @@ -102,32 +114,34 @@ class AbducerBase(abc.ABC): if max_address_num == -1: max_address_num = len(pred_res) - if self.cache and (tuple(pred_res), key) in self.cache_min_address_num: - address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), key)] + require_more_address) - if (tuple(pred_res), key, address_num) in self.cache_candidates: - candidates = self.cache_candidates[(tuple(pred_res), key, address_num)] + if self.cache and (tuple(self.flatten(pred_res)), key) in self.cache_min_address_num: + address_num = min(max_address_num, self.cache_min_address_num[(tuple(self.flatten(pred_res)), key)] + require_more_address) + if (tuple(self.flatten(pred_res)), key, address_num) in self.cache_candidates: + candidates = self.cache_candidates[(tuple(self.flatten(pred_res)), key, address_num)] if self.zoopt: return candidates[0] else: - return self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) + return self.get_one_candidate(pred_res, pred_res_prob, candidates) if self.zoopt: address_idx, address_num = self.zoopt_get_address_idx(pred_res, key, max_address_num) - candidates = self.kb.address_by_idx(pred_res, key, address_idx) + candidates = self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) min_address_num = address_num - candidate = candidates[0] else: - candidates, min_address_num, address_num = self.kb.abduce_candidates(pred_res, key, max_address_num, require_more_address) - candidate = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) + candidates, min_address_num, address_num = self.kb.abduce_candidates(pred_res, key, max_address_num, require_more_address, self.multiple_predictions) + + candidate = self.get_one_candidate(pred_res, pred_res_prob, candidates) if self.cache: - self.cache_min_address_num[(tuple(pred_res), key)] = min_address_num - self.cache_candidates[(tuple(pred_res), key, address_num)] = candidates + self.cache_min_address_num[(tuple(self.flatten(pred_res)), key)] = min_address_num + self.cache_candidates[(tuple(self.flatten(pred_res)), key, address_num)] = candidates - return candidate + def abduce_rules(self, pred_res): + return self.kb.abduce_rules(pred_res) + def batch_abduce(self, Z, Y, max_address_num = -1, require_more_address = 0): return [ @@ -185,7 +199,7 @@ if __name__ == '__main__': print(res) print() - kb = hwf_KB(len_list = [1, 3, 5]) + kb = HWF_KB(len_list = [1, 3, 5]) abd = AbducerBase(kb, 'hamming') res = abd.abduce((['5', '+', '2'], None, 3), max_address_num = 2, require_more_address = 0) print(res) @@ -197,3 +211,23 @@ if __name__ == '__main__': print(res) print() + kb = HED_prolog_KB() + abd = AbducerBase(kb, zoopt=True, multiple_predictions=True) + consist_re = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 0, '=', 1, 1]] + consist_re2 = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 1, '=', 1, 1]] # not consistent with rules + inconsist_re = [[1, '+', 0, '=', 0], [1, '=', 1, '=', 0], [0, '=', 0, '=', 1, 1]] + rules = ['my_op([0], [0], [1, 1])', 'my_op([1], [1], [0])', 'my_op([1], [0], [0])'] + + print(kb.logic_forward(consist_re), kb.logic_forward(inconsist_re)) + print(kb.consist_rule(consist_re, rules), kb.consist_rule(consist_re2, rules)) + print() + + res = abd.abduce((consist_re, None, None)) + print(res) + res = abd.abduce((inconsist_re, None, None)) + print(res) + print() + + abduced_rules = abd.abduce_rules(consist_re) + print(abduced_rules) + From 734a81834a197e7fe2181d2dbc4bd2847f99f866 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 7 Dec 2022 12:56:27 +0800 Subject: [PATCH 100/601] Add kb and abducer for HED --- abducer/abducer_base.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 8fde5a1..322f200 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -213,21 +213,21 @@ if __name__ == '__main__': kb = HED_prolog_KB() abd = AbducerBase(kb, zoopt=True, multiple_predictions=True) - consist_re = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 0, '=', 1, 1]] - consist_re2 = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 1, '=', 1, 1]] # not consistent with rules - inconsist_re = [[1, '+', 0, '=', 0], [1, '=', 1, '=', 0], [0, '=', 0, '=', 1, 1]] + consist_exs = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 0, '=', 1, 1]] + consist_exs2 = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 1, '=', 1, 1]] # not consistent with rules + inconsist_exs = [[1, '+', 0, '=', 0], [1, '=', 1, '=', 0], [0, '=', 0, '=', 1, 1]] rules = ['my_op([0], [0], [1, 1])', 'my_op([1], [1], [0])', 'my_op([1], [0], [0])'] - print(kb.logic_forward(consist_re), kb.logic_forward(inconsist_re)) - print(kb.consist_rule(consist_re, rules), kb.consist_rule(consist_re2, rules)) + print(kb.logic_forward(consist_exs), kb.logic_forward(inconsist_exs)) + print(kb.consist_rule(consist_exs, rules), kb.consist_rule(consist_exs2, rules)) print() - res = abd.abduce((consist_re, None, None)) + res = abd.abduce((consist_exs, None, None)) print(res) - res = abd.abduce((inconsist_re, None, None)) + res = abd.abduce((inconsist_exs, None, None)) print(res) print() - abduced_rules = abd.abduce_rules(consist_re) + abduced_rules = abd.abduce_rules(consist_exs) print(abduced_rules) From 22b11315a1af851440fd858a28867fae2e961f51 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 7 Dec 2022 13:26:22 +0800 Subject: [PATCH 101/601] Update kb.py --- abducer/kb.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/abducer/kb.py b/abducer/kb.py index 9ae8efd..4bcf448 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -43,12 +43,18 @@ class KBBase(ABC): new_candidates += candidates return new_candidates + def correct_result(self, pred_res, key): + if type(key) == int: + return abs(self.logic_forward(pred_res) - key) <= 1e-3 + else: + return self.logic_forward(pred_res) == key + def abduction(self, pred_res, key, max_address_num, require_more_address, multiple_predictions = False): candidates = [] for address_num in range(len(pred_res) + 1): if address_num == 0: - if abs(self.logic_forward(pred_res) - key) <= 1e-3: + if self.correct_result(pred_res, key): candidates.append(pred_res) else: new_candidates = self.address(address_num, pred_res, key, multiple_predictions) From 4ed250ea19a01fd808308a29559d8a0970af2325 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 7 Dec 2022 13:27:08 +0800 Subject: [PATCH 102/601] Update abducer_base.py --- abducer/abducer_base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 322f200..3dd4822 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -222,9 +222,9 @@ if __name__ == '__main__': print(kb.consist_rule(consist_exs, rules), kb.consist_rule(consist_exs2, rules)) print() - res = abd.abduce((consist_exs, None, None)) + res = abd.abduce((consist_exs, True, None)) print(res) - res = abd.abduce((inconsist_exs, None, None)) + res = abd.abduce((inconsist_exs, True, None)) print(res) print() From 6b1ca5d9d9bd0f64dda7a5cdc02d03100caac437 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 7 Dec 2022 13:35:42 +0800 Subject: [PATCH 103/601] Fix bugs for non-zoopt option --- abducer/abducer_base.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 3dd4822..5060529 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -212,7 +212,7 @@ if __name__ == '__main__': print() kb = HED_prolog_KB() - abd = AbducerBase(kb, zoopt=True, multiple_predictions=True) + abd = AbducerBase(kb, zoopt=False, multiple_predictions=True) consist_exs = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 0, '=', 1, 1]] consist_exs2 = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 1, '=', 1, 1]] # not consistent with rules inconsist_exs = [[1, '+', 0, '=', 0], [1, '=', 1, '=', 0], [0, '=', 0, '=', 1, 1]] @@ -222,9 +222,9 @@ if __name__ == '__main__': print(kb.consist_rule(consist_exs, rules), kb.consist_rule(consist_exs2, rules)) print() - res = abd.abduce((consist_exs, True, None)) + res = abd.abduce((consist_exs, None, True)) print(res) - res = abd.abduce((inconsist_exs, True, None)) + res = abd.abduce((inconsist_exs, None, True)) print(res) print() From 01ac0b8dd1fce2e15c4af97a53c5892f7f7a4d4b Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 7 Dec 2022 13:36:00 +0800 Subject: [PATCH 104/601] Fix bugs for non-zoopt option --- abducer/kb.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 4bcf448..7ade7f9 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -36,7 +36,10 @@ class KBBase(ABC): def address(self, address_num, pred_res, key, multiple_predictions = False): new_candidates = [] - address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) + if not multiple_predictions: + address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) + else: + address_idx_list = list(combinations(list(range(len(self.flatten(pred_res)))), address_num)) for address_idx in address_idx_list: candidates = self.address_by_idx(pred_res, key, address_idx, multiple_predictions) @@ -44,10 +47,10 @@ class KBBase(ABC): return new_candidates def correct_result(self, pred_res, key): - if type(key) == int: + if type(key) != bool: return abs(self.logic_forward(pred_res) - key) <= 1e-3 else: - return self.logic_forward(pred_res) == key + return self.logic_forward(pred_res) def abduction(self, pred_res, key, max_address_num, require_more_address, multiple_predictions = False): candidates = [] From 3bd27a45ba23a15ee57328297f17fbbe48874078 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 7 Dec 2022 18:49:07 +0800 Subject: [PATCH 105/601] Update abducer_base.py --- abducer/abducer_base.py | 119 +++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 63 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 5060529..e087377 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -11,12 +11,14 @@ #================================================================# import sys +sys.path.append(".") sys.path.append("..") import abc -from abducer.kb import add_KB, HWF_KB, add_prolog_KB, HED_prolog_KB +from abducer.kb import * import numpy as np from zoopt import Dimension, Objective, Parameter, Opt +from utils.utils import _confidence_dist, _flatten, _hamming_dist import time @@ -32,72 +34,44 @@ class AbducerBase(abc.ABC): if self.cache: self.cache_min_address_num = {} self.cache_candidates = {} - - - def hamming_dist(self, A, B): - B = np.array(B) - A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) - return np.sum(A != B, axis = 1) - def confidence_dist(self, A, B): - mapping = dict(zip(self.kb.pseudo_label_list, list(range(len(self.kb.pseudo_label_list))))) - B = [list(map(lambda x : mapping[x], b)) for b in B] - - B = np.array(B) - A = np.clip(A, 1e-9, 1) - A = np.expand_dims(A, axis=0) - A = A.repeat(axis=0, repeats=(len(B))) - rows = np.array(range(len(B))) - rows = np.expand_dims(rows, axis = 1).repeat(axis = 1, repeats = len(B[0])) - cols = np.array(range(len(B[0]))) - cols = np.expand_dims(cols, axis = 0).repeat(axis = 0, repeats = len(B)) - return 1 - np.prod(A[rows, cols, B], axis = 1) - def get_cost_list(self, pred_res, pred_res_prob, candidates): + def _get_cost_list(self, pred_res, pred_res_prob, candidates): if self.dist_func == 'hamming': - return self.hamming_dist(pred_res, candidates) + return _hamming_dist(pred_res, candidates) elif self.dist_func == 'confidence': - return self.confidence_dist(pred_res_prob, candidates) + mapping = dict(zip(self.kb.pseudo_label_list, list(range(len(self.kb.pseudo_label_list))))) + return _confidence_dist(pred_res_prob, [list(map(lambda x : mapping[x], c)) for c in candidates]) - def get_one_candidate(self, pred_res, pred_res_prob, candidates): + def _get_one_candidate(self, pred_res, pred_res_prob, candidates): if len(candidates) == 0: return [] elif len(candidates) == 1 or self.zoopt: return candidates[0] else: - cost_list = self.get_cost_list(pred_res, pred_res_prob, candidates) + cost_list = self._get_cost_list(pred_res, pred_res_prob, candidates) min_address_num = np.min(cost_list) idxs = np.where(cost_list == min_address_num)[0] return [candidates[idx] for idx in idxs][0] - - - - # for multiple_prediction - def flatten(self, l): - if self.multiple_predictions: - return [item for sublist in l for item in sublist] - else: - return l - - # for zoopt - def zoopt_address_score(self, pred_res, key, address_idx): + def _zoopt_address_score(self, pred_res, key, address_idx): candidates = self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) return 0 if len(candidates) > 0 else 1 - def constraint_address_num(self, solution, max_address_num): + def _constrain_address_num(self, solution, max_address_num): x = solution.get_x() return max_address_num - x.sum() - def zoopt_get_address_idx(self, pred_res, key, max_address_num): - dimension = Dimension(size=len(self.flatten(pred_res)), - regs=[[0, 1]] * len(self.flatten(pred_res)), - tys=[False] * len(self.flatten(pred_res))) - objective = Objective(lambda sol: self.zoopt_address_score(pred_res, key, [idx for idx, i in enumerate(sol.get_x()) if i != 0]), + def _zoopt_get_address_idx(self, pred_res, key, max_address_num): + length = len(_flatten(pred_res)) + dimension = Dimension(size=length, + regs=[[0, 1]] * length, + tys=[False] * length) + objective = Objective(lambda sol: self._zoopt_address_score(pred_res, key, [idx for idx, i in enumerate(sol.get_x()) if i != 0]), dim=dimension, - constraint=lambda sol: self.constraint_address_num(sol, max_address_num)) + constraint=lambda sol: self._constrain_address_num(sol, max_address_num)) parameter = Parameter(budget=100 * dimension.get_size(), autoset=True) solution = Opt.min(objective, parameter).get_x() @@ -107,35 +81,51 @@ class AbducerBase(abc.ABC): return address_idx, address_num + def _get_cache(self, data, max_address_num, require_more_address): + pred_res, pred_res_prob, key = data + if self.multiple_predictions: + pred_res = _flatten(pred_res) + key = tuple(key) + if (tuple(pred_res), key) in self.cache_min_address_num: + address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), key)] + require_more_address) + if (tuple(pred_res), key, address_num) in self.cache_candidates: + candidates = self.cache_candidates[(tuple(pred_res), key, address_num)] + if self.zoopt: + return candidates[0] + else: + return self._get_one_candidate(pred_res, pred_res_prob, candidates) + return None + + def _set_cache(self, pred_res, key, min_address_num, address_num, candidates): + if self.multiple_predictions: + pred_res = _flatten(pred_res) + key = tuple(key) + self.cache_min_address_num[(tuple(pred_res), key)] = min_address_num + self.cache_candidates[(tuple(pred_res), key, address_num)] = candidates def abduce(self, data, max_address_num = -1, require_more_address = 0): pred_res, pred_res_prob, key = data if max_address_num == -1: - max_address_num = len(pred_res) - - if self.cache and (tuple(self.flatten(pred_res)), key) in self.cache_min_address_num: - address_num = min(max_address_num, self.cache_min_address_num[(tuple(self.flatten(pred_res)), key)] + require_more_address) - if (tuple(self.flatten(pred_res)), key, address_num) in self.cache_candidates: - candidates = self.cache_candidates[(tuple(self.flatten(pred_res)), key, address_num)] - if self.zoopt: - return candidates[0] - else: - return self.get_one_candidate(pred_res, pred_res_prob, candidates) + max_address_num = len(_flatten(pred_res)) + if self.cache: + candidate = self._get_cache(data, max_address_num, require_more_address) + if candidate is not None: + return candidate + if self.zoopt: - address_idx, address_num = self.zoopt_get_address_idx(pred_res, key, max_address_num) + address_idx, address_num = self._zoopt_get_address_idx(pred_res, key, max_address_num) candidates = self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) min_address_num = address_num else: candidates, min_address_num, address_num = self.kb.abduce_candidates(pred_res, key, max_address_num, require_more_address, self.multiple_predictions) - candidate = self.get_one_candidate(pred_res, pred_res_prob, candidates) + candidate = self._get_one_candidate(pred_res, pred_res_prob, candidates) if self.cache: - self.cache_min_address_num[(tuple(self.flatten(pred_res)), key)] = min_address_num - self.cache_candidates[(tuple(self.flatten(pred_res)), key, address_num)] = candidates + self._set_cache(pred_res, key, min_address_num, address_num, candidates) return candidate @@ -144,10 +134,13 @@ class AbducerBase(abc.ABC): def batch_abduce(self, Z, Y, max_address_num = -1, require_more_address = 0): - return [ + if self.multiple_predictions: + return self.abduce((Z['cls'], Z['prob'], Y), max_address_num, require_more_address) + else: + return [ self.abduce((z, prob, y), max_address_num, require_more_address)\ for z, prob, y in zip(Z['cls'], Z['prob'], Y) - ] + ] def __call__(self, Z, Y, max_address_num = -1, require_more_address = 0): return self.batch_abduce(Z, Y, max_address_num, require_more_address) @@ -212,7 +205,7 @@ if __name__ == '__main__': print() kb = HED_prolog_KB() - abd = AbducerBase(kb, zoopt=False, multiple_predictions=True) + abd = AbducerBase(kb, zoopt=True, multiple_predictions=True) consist_exs = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 0, '=', 1, 1]] consist_exs2 = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 1, '=', 1, 1]] # not consistent with rules inconsist_exs = [[1, '+', 0, '=', 0], [1, '=', 1, '=', 0], [0, '=', 0, '=', 1, 1]] @@ -222,9 +215,9 @@ if __name__ == '__main__': print(kb.consist_rule(consist_exs, rules), kb.consist_rule(consist_exs2, rules)) print() - res = abd.abduce((consist_exs, None, True)) + res = abd.abduce((consist_exs, None, [1] * len(consist_exs))) print(res) - res = abd.abduce((inconsist_exs, None, True)) + res = abd.abduce((inconsist_exs, None, [1] * len(consist_exs))) print(res) print() From d4ef2ca8d9730e03a0d5307977e273ff226f021f Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 7 Dec 2022 18:49:23 +0800 Subject: [PATCH 106/601] Update kb.py --- abducer/kb.py | 72 ++++++++++++++++++--------------------------------- 1 file changed, 25 insertions(+), 47 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 7ade7f9..f44ffec 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -15,8 +15,12 @@ import bisect import copy import numpy as np +import sys +sys.path.append("..") + from collections import defaultdict from itertools import product, combinations +from utils.utils import _flatten, _reform_ids, _hamming_dist import pyswip @@ -39,25 +43,21 @@ class KBBase(ABC): if not multiple_predictions: address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) else: - address_idx_list = list(combinations(list(range(len(self.flatten(pred_res)))), address_num)) + address_idx_list = list(combinations(list(range(len(_flatten(pred_res)))), address_num)) for address_idx in address_idx_list: candidates = self.address_by_idx(pred_res, key, address_idx, multiple_predictions) new_candidates += candidates return new_candidates - def correct_result(self, pred_res, key): - if type(key) != bool: - return abs(self.logic_forward(pred_res) - key) <= 1e-3 - else: - return self.logic_forward(pred_res) + def abduction(self, pred_res, key, max_address_num, require_more_address, multiple_predictions = False): candidates = [] for address_num in range(len(pred_res) + 1): if address_num == 0: - if self.correct_result(pred_res, key): + if abs(self.logic_forward(pred_res) - key) <= 1e-3: candidates.append(pred_res) else: new_candidates = self.address(address_num, pred_res, key, multiple_predictions) @@ -79,23 +79,7 @@ class KBBase(ABC): return candidates, min_address_num, address_num - # for multiple predictions, modify from `learn_add.py` - def flatten(self, l): - return [item for sublist in l for item in sublist] - - # for multiple predictions, modify from `learn_add.py` - def reform_ids(self, flatten_pred_res, save_pred_res): - re = [] - i = 0 - for e in save_pred_res: - j = 0 - ids = [] - while j < len(e): - ids.append(flatten_pred_res[i + j]) - j += 1 - re.append(ids) - i = i + j - return re + def __len__(self): pass @@ -110,7 +94,7 @@ class ClsKB(KBBase): if GKB_flag: self.base = {} - X, Y = self.get_GKB(self.pseudo_label_list, self.len_list) + X, Y = self._get_GKB(self.pseudo_label_list, self.len_list) for x, y in zip(X, Y): self.base.setdefault(len(x), defaultdict(list))[y].append(x) else: @@ -118,7 +102,7 @@ class ClsKB(KBBase): for address_num in range(max(self.len_list) + 1): self.all_address_candidate_dict[address_num] = list(product(self.pseudo_label_list, repeat = address_num)) - def get_GKB(self, pseudo_label_list, len_list): + def _get_GKB(self, pseudo_label_list, len_list): all_X = [] for len in len_list: all_X += list(product(pseudo_label_list, repeat = len)) @@ -142,12 +126,6 @@ class ClsKB(KBBase): return self.abduction(pred_res, key, max_address_num, require_more_address, multiple_predictions) - - def hamming_dist(self, A, B): - B = np.array(B) - A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) - return np.sum(A != B, axis = 1) - def abduce_from_GKB(self, pred_res, key, max_address_num, require_more_address): if self.base == {} or len(pred_res) not in self.len_list: return [] @@ -159,7 +137,7 @@ class ClsKB(KBBase): min_address_num = 0 address_num = 0 else: - cost_list = self.hamming_dist(pred_res, all_candidates) + cost_list = _hamming_dist(pred_res, all_candidates) min_address_num = np.min(cost_list) address_num = min(max_address_num, min_address_num + require_more_address) idxs = np.where(cost_list <= address_num)[0] @@ -174,7 +152,7 @@ class ClsKB(KBBase): if multiple_predictions: save_pred_res = pred_res - pred_res = self.flatten(pred_res) + pred_res = _flatten(pred_res) for c in abduce_c: candidate = pred_res.copy() @@ -182,7 +160,7 @@ class ClsKB(KBBase): candidate[idx] = c[i] if multiple_predictions: - candidate = self.reform_ids(candidate, save_pred_res) + candidate = _reform_ids(candidate, save_pred_res) if self.logic_forward(candidate) == key: candidates.append(candidate) @@ -252,15 +230,15 @@ class prolog_KB(KBBase): def address_by_idx(self, pred_res, key, address_idx, multiple_predictions = False): candidates = [] - + # print(address_idx) if not multiple_predictions: query_string = self.get_query_string(pred_res, key, address_idx) else: - query_string = self.get_query_string_need_flatten(pred_res, key, address_idx) + query_string = self.get_query_string_need__flatten(pred_res, key, address_idx) if multiple_predictions: save_pred_res = pred_res - pred_res = self.flatten(pred_res) + pred_res = _flatten(pred_res) abduce_c = [list(z.values()) for z in list(self.prolog.query(query_string))] for c in abduce_c: @@ -269,7 +247,7 @@ class prolog_KB(KBBase): candidate[idx] = c[i] if multiple_predictions: - candidate = self.reform_ids(candidate, save_pred_res) + candidate = _reform_ids(candidate, save_pred_res) candidates.append(candidate) return candidates @@ -297,22 +275,22 @@ class add_prolog_KB(prolog_KB): class HED_prolog_KB(prolog_KB): def __init__(self, pseudo_label_list = [0, 1, '+', '=']): super().__init__(pseudo_label_list) - self.prolog.consult('../datasets/hed/learn_add.pl') + self.prolog.consult('./datasets/hed/learn_add.pl') # corresponding to `con_sol is not None` in `consistent_score_mapped` within `learn_add.py` def logic_forward(self, exs): return len(list(self.prolog.query("abduce_consistent_insts(%s)." % exs))) != 0 - def get_query_string_need_flatten(self, pred_res, key, address_idx): - # flatten - flatten_pred_res = self.flatten(pred_res) + def get_query_string_need__flatten(self, pred_res, key, address_idx): + # _flatten + _flatten_pred_res = _flatten(pred_res) # add variables for prolog - for idx in range(len(flatten_pred_res)): + for idx in range(len(_flatten_pred_res)): if idx in address_idx: - flatten_pred_res[idx] = 'X' + str(idx) - # unflatten - new_pred_res = self.reform_ids(flatten_pred_res, pred_res) + _flatten_pred_res[idx] = 'X' + str(idx) + # un_flatten + new_pred_res = _reform_ids(_flatten_pred_res, pred_res) query_string = "abduce_consistent_insts(%s)." % new_pred_res return query_string.replace("'", "").replace("+", "'+'").replace("=", "'='") From 9ffb1707c0c4cc478db0438cc00215c3587d977b Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 7 Dec 2022 18:49:53 +0800 Subject: [PATCH 107/601] Create utils.py --- utils/utils.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 utils/utils.py diff --git a/utils/utils.py b/utils/utils.py new file mode 100644 index 0000000..742dc03 --- /dev/null +++ b/utils/utils.py @@ -0,0 +1,35 @@ +import numpy as np + +# for multiple predictions, modify from `learn_add.py` +def _flatten(l): + return [item for sublist in l for item in _flatten(sublist)] if isinstance(l, list) else [l] + +# for multiple predictions, modify from `learn_add.py` +def _reform_ids(flatten_pred_res, save_pred_res): + re = [] + i = 0 + for e in save_pred_res: + j = 0 + ids = [] + while j < len(e): + ids.append(flatten_pred_res[i + j]) + j += 1 + re.append(ids) + i = i + j + return re + +def _hamming_dist(A, B): + B = np.array(B) + A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) + return np.sum(A != B, axis = 1) + +def _confidence_dist(A, B): + B = np.array(B) + A = np.clip(A, 1e-9, 1) + A = np.expand_dims(A, axis=0) + A = A.repeat(axis=0, repeats=(len(B))) + rows = np.array(range(len(B))) + rows = np.expand_dims(rows, axis = 1).repeat(axis = 1, repeats = len(B[0])) + cols = np.array(range(len(B[0]))) + cols = np.expand_dims(cols, axis = 0).repeat(axis = 0, repeats = len(B)) + return 1 - np.prod(A[rows, cols, B], axis = 1) From 499e582982dde08b69a546e82ed6652b40cb32a4 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 7 Dec 2022 18:50:46 +0800 Subject: [PATCH 108/601] Delete utils.py --- utils/utils.py | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 utils/utils.py diff --git a/utils/utils.py b/utils/utils.py deleted file mode 100644 index 742dc03..0000000 --- a/utils/utils.py +++ /dev/null @@ -1,35 +0,0 @@ -import numpy as np - -# for multiple predictions, modify from `learn_add.py` -def _flatten(l): - return [item for sublist in l for item in _flatten(sublist)] if isinstance(l, list) else [l] - -# for multiple predictions, modify from `learn_add.py` -def _reform_ids(flatten_pred_res, save_pred_res): - re = [] - i = 0 - for e in save_pred_res: - j = 0 - ids = [] - while j < len(e): - ids.append(flatten_pred_res[i + j]) - j += 1 - re.append(ids) - i = i + j - return re - -def _hamming_dist(A, B): - B = np.array(B) - A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) - return np.sum(A != B, axis = 1) - -def _confidence_dist(A, B): - B = np.array(B) - A = np.clip(A, 1e-9, 1) - A = np.expand_dims(A, axis=0) - A = A.repeat(axis=0, repeats=(len(B))) - rows = np.array(range(len(B))) - rows = np.expand_dims(rows, axis = 1).repeat(axis = 1, repeats = len(B[0])) - cols = np.array(range(len(B[0]))) - cols = np.expand_dims(cols, axis = 0).repeat(axis = 0, repeats = len(B)) - return 1 - np.prod(A[rows, cols, B], axis = 1) From 83a4258e8681c71ee9ecff2abf2757e1fafaa75c Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 7 Dec 2022 18:51:21 +0800 Subject: [PATCH 109/601] Create utils.py --- utils/utils.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 utils/utils.py diff --git a/utils/utils.py b/utils/utils.py new file mode 100644 index 0000000..742dc03 --- /dev/null +++ b/utils/utils.py @@ -0,0 +1,35 @@ +import numpy as np + +# for multiple predictions, modify from `learn_add.py` +def _flatten(l): + return [item for sublist in l for item in _flatten(sublist)] if isinstance(l, list) else [l] + +# for multiple predictions, modify from `learn_add.py` +def _reform_ids(flatten_pred_res, save_pred_res): + re = [] + i = 0 + for e in save_pred_res: + j = 0 + ids = [] + while j < len(e): + ids.append(flatten_pred_res[i + j]) + j += 1 + re.append(ids) + i = i + j + return re + +def _hamming_dist(A, B): + B = np.array(B) + A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) + return np.sum(A != B, axis = 1) + +def _confidence_dist(A, B): + B = np.array(B) + A = np.clip(A, 1e-9, 1) + A = np.expand_dims(A, axis=0) + A = A.repeat(axis=0, repeats=(len(B))) + rows = np.array(range(len(B))) + rows = np.expand_dims(rows, axis = 1).repeat(axis = 1, repeats = len(B[0])) + cols = np.array(range(len(B[0]))) + cols = np.expand_dims(cols, axis = 0).repeat(axis = 0, repeats = len(B)) + return 1 - np.prod(A[rows, cols, B], axis = 1) From 2f2dd6d1fa2f463156ad7bceb6d75ae9175afbd2 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 7 Dec 2022 18:54:14 +0800 Subject: [PATCH 110/601] Update readme.md --- readme.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index e3726a9..279257b 100644 --- a/readme.md +++ b/readme.md @@ -3,7 +3,17 @@ This is the code repository of abductive learning Package. ## Environment dependency -... + +#### Install Swipl +[http://www.swi-prolog.org/build/unix.html](http://www.swi-prolog.org/build/unix.html) + +#### Install required package + +```shell +pip install zoopt +pip install pyswip==0.2.9 +``` + ## Example share_example.py and nonshare_exaple.py are examples of grounded abductive learning. From 6a88da10344f49cdf6db7b7a7f6320d11fbedb16 Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Thu, 8 Dec 2022 12:14:03 +0800 Subject: [PATCH 111/601] update parallel versio of get GKB --- abducer/kb.py | 53 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index f44ffec..9e28283 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -22,6 +22,8 @@ from collections import defaultdict from itertools import product, combinations from utils.utils import _flatten, _reform_ids, _hamming_dist +from multiprocessing import Pool + import pyswip @@ -102,18 +104,44 @@ class ClsKB(KBBase): for address_num in range(max(self.len_list) + 1): self.all_address_candidate_dict[address_num] = list(product(self.pseudo_label_list, repeat = address_num)) - def _get_GKB(self, pseudo_label_list, len_list): - all_X = [] - for len in len_list: - all_X += list(product(pseudo_label_list, repeat = len)) - - X = [] - Y = [] - for x in all_X: + # For parallel version of _get_GKB + def _get_XY_list(self, args): + pre_x, post_x_it = args[0], args[1] + XY_list = [] + for post_x in post_x_it: + x = (pre_x,) + post_x y = self.logic_forward(x) if y != np.inf: - X.append(x) - Y.append(y) + XY_list.append((x,y)) + return XY_list + + # Parallel get GKB + def _get_GKB(self, pseudo_label_list, len_list): + # all_X = [] + # for length in len_list: + # all_X += list(product(pseudo_label_list, repeat = length)) + + # X, Y = [], [] + # for x in all_X: + # y = self.logic_forward(x) + # if y != np.inf: + # X.append(x) + # Y.append(y) + + X, Y = [], [] + for length in len_list: + arg_list = [] + for pre_x in pseudo_label_list: + post_x_it = product(pseudo_label_list, repeat = length-1) + arg_list.append((pre_x, post_x_it)) + with Pool(processes=len(arg_list)) as pool: + ret_list = pool.map(self._get_XY_list, arg_list) + for XY_list in ret_list: + if len(XY_list) == 0: + continue + part_X, part_Y = zip(*XY_list) + X.extend(part_X) + Y.extend(part_Y) return X, Y def logic_forward(self): @@ -366,7 +394,10 @@ class RegKB(KBBase): import time if __name__ == "__main__": - pass + t1 = time.time() + kb = HWF_KB(True) + t2 = time.time() + print(t2-t1) # X = ["1+1", "0+1", "1+0", "2+0", "1+0+1"] From 903ec6801bfe389241819e2bca8c34b080528eb7 Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Fri, 9 Dec 2022 10:52:21 +0800 Subject: [PATCH 112/601] add lint actions --- .github/workflows/lint.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..aac5232 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,17 @@ +name: flake8 Lint + +on: [push, pull_request] + +jobs: + flake8-lint: + runs-on: ubuntu-latest + name: Lint + steps: + - name: Check out source repository + uses: actions/checkout@v3 + - name: Set up Python environment + uses: actions/setup-python@v4 + with: + python-version: "3.11" + - name: flake8 Lint + uses: py-actions/flake8@v2 \ No newline at end of file From 7457e083017d7aa7b87b509f536679ae094d8782 Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Fri, 9 Dec 2022 11:05:29 +0800 Subject: [PATCH 113/601] update actions --- .github/workflows/lint.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index aac5232..a15aea1 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -12,6 +12,10 @@ jobs: - name: Set up Python environment uses: actions/setup-python@v4 with: - python-version: "3.11" + python-version: "3.8" - name: flake8 Lint - uses: py-actions/flake8@v2 \ No newline at end of file + uses: py-actions/flake8@v2 + with: + max-line-length: "100" + path: "src" + plugins: "flake8-bugbear==22.1.11 flake8-black" \ No newline at end of file From 3904293bf91ac82825b592df1058309a8f4c6de7 Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Fri, 9 Dec 2022 11:09:08 +0800 Subject: [PATCH 114/601] update actions --- .github/workflows/lint.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index a15aea1..7b4a1c4 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,5 +17,4 @@ jobs: uses: py-actions/flake8@v2 with: max-line-length: "100" - path: "src" - plugins: "flake8-bugbear==22.1.11 flake8-black" \ No newline at end of file + plugins: "flake8-bugbear" \ No newline at end of file From 8c9a40f359ea08183a589fe1627a6dbc899da64b Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Fri, 9 Dec 2022 11:19:33 +0800 Subject: [PATCH 115/601] update badge --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 279257b..3d343de 100644 --- a/readme.md +++ b/readme.md @@ -1,3 +1,5 @@ +[![flake8 Lint](https://github.com/AbductiveLearning/ABL-Package/actions/workflows/lint.yml/badge.svg?branch=Dev)](https://github.com/AbductiveLearning/ABL-Package/actions/workflows/lint.yml) + # ABL Package This is the code repository of abductive learning Package. From f59148a8ff9627643472e53163c031b893e9e093 Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Fri, 9 Dec 2022 11:33:57 +0800 Subject: [PATCH 116/601] update badge --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7b4a1c4..7db534f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -16,5 +16,5 @@ jobs: - name: flake8 Lint uses: py-actions/flake8@v2 with: - max-line-length: "100" + max-line-length: "110" plugins: "flake8-bugbear" \ No newline at end of file From fd6d7769717e31c4d6acb018257250ea445f2047 Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Fri, 9 Dec 2022 16:13:34 +0800 Subject: [PATCH 117/601] update badge --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7db534f..e90dfad 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,4 +17,4 @@ jobs: uses: py-actions/flake8@v2 with: max-line-length: "110" - plugins: "flake8-bugbear" \ No newline at end of file + plugins: "flake8-bugbear flake8-black" \ No newline at end of file From 8c169e10aabf2d4b5fcffbc3cd66a554cea7710a Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Fri, 9 Dec 2022 16:18:58 +0800 Subject: [PATCH 118/601] update badge --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 3d343de..512a68f 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,5 @@ [![flake8 Lint](https://github.com/AbductiveLearning/ABL-Package/actions/workflows/lint.yml/badge.svg?branch=Dev)](https://github.com/AbductiveLearning/ABL-Package/actions/workflows/lint.yml) +[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) # ABL Package From a583ab94e7b9f8cc424fec12d41a145d0c0f00ea Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Sat, 10 Dec 2022 22:06:22 +0800 Subject: [PATCH 119/601] Change zoopt score for multiple predictions --- abducer/abducer_base.py | 182 +++++++++++++++++++++------------------- 1 file changed, 98 insertions(+), 84 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index e087377..1e8522d 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -1,16 +1,17 @@ # coding: utf-8 -#================================================================# +# ================================================================# # Copyright (C) 2021 Freecss All rights reserved. -# +# # File Name :abducer_base.py # Author :freecss # Email :karlfreecss@gmail.com # Created Date :2021/06/03 # Description : # -#================================================================# +# ================================================================# import sys + sys.path.append(".") sys.path.append("..") @@ -18,30 +19,31 @@ import abc from abducer.kb import * import numpy as np from zoopt import Dimension, Objective, Parameter, Opt -from utils.utils import _confidence_dist, _flatten, _hamming_dist +from utils.utils import confidence_dist, flatten, hamming_dist +import math import time + class AbducerBase(abc.ABC): - def __init__(self, kb, dist_func = 'confidence', zoopt = False, multiple_predictions = False, cache = True): + def __init__(self, kb, dist_func='confidence', zoopt=False, multiple_predictions=False, cache=True): self.kb = kb - assert(dist_func == 'hamming' or dist_func == 'confidence') - self.dist_func = dist_func + assert dist_func == 'hamming' or dist_func == 'confidence' + self.dist_func = dist_func self.zoopt = zoopt self.multiple_predictions = multiple_predictions self.cache = cache - + if self.cache: self.cache_min_address_num = {} self.cache_candidates = {} - def _get_cost_list(self, pred_res, pred_res_prob, candidates): if self.dist_func == 'hamming': - return _hamming_dist(pred_res, candidates) + return hamming_dist(pred_res, candidates) elif self.dist_func == 'confidence': mapping = dict(zip(self.kb.pseudo_label_list, list(range(len(self.kb.pseudo_label_list))))) - return _confidence_dist(pred_res_prob, [list(map(lambda x : mapping[x], c)) for c in candidates]) + return confidence_dist(pred_res_prob, [list(map(lambda x: mapping[x], c)) for c in candidates]) def _get_one_candidate(self, pred_res, pred_res_prob, candidates): if len(candidates) == 0: @@ -54,37 +56,46 @@ class AbducerBase(abc.ABC): idxs = np.where(cost_list == min_address_num)[0] return [candidates[idx] for idx in idxs][0] - - # for zoopt - def _zoopt_address_score(self, pred_res, key, address_idx): - candidates = self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) - return 0 if len(candidates) > 0 else 1 - + # for zoopt + def _zoopt_score_multiple(self, pred_res, key, solution): + all_address_flag = reform_idx(solution, pred_res) + score = 0 + for idx in enumerate(len(pred_res)): + address_idx = [i for i, flag in enumerate(all_address_flag[idx]) if flag != 0] + candidate = self.kb.address_by_idx([pred_res[idx]], key[idx], address_idx, True) + if len(candidate) > 0: + score += 1 + return score + + def _zoopt_address_score(self, pred_res, key, sol): + if not self.multiple_predictions: + address_idx = [idx for idx, i in enumerate(sol.get_x()) if i != 0] + candidates = self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) + return 1 if len(candidates) > 0 else 0 + else: + return self._zoopt_score_multiple(pred_res, key, sol.get_x()) + def _constrain_address_num(self, solution, max_address_num): x = solution.get_x() return max_address_num - x.sum() - def _zoopt_get_address_idx(self, pred_res, key, max_address_num): - length = len(_flatten(pred_res)) - dimension = Dimension(size=length, - regs=[[0, 1]] * length, - tys=[False] * length) - objective = Objective(lambda sol: self._zoopt_address_score(pred_res, key, [idx for idx, i in enumerate(sol.get_x()) if i != 0]), - dim=dimension, - constraint=lambda sol: self._constrain_address_num(sol, max_address_num)) - parameter = Parameter(budget=100 * dimension.get_size(), autoset=True) + def zoopt_get_solution(self, pred_res, key, max_address_num): + length = len(flatten(pred_res)) + dimension = Dimension(size=length, regs=[[0, 1]] * length, tys=[False] * length) + objective = Objective( + lambda sol: -self._zoopt_address_score(pred_res, key, sol), + dim=dimension, + constraint=lambda sol: self._constrain_address_num(sol, max_address_num), + ) + parameter = Parameter(budget=100, autoset=True) solution = Opt.min(objective, parameter).get_x() - - address_idx = [idx for idx, i in enumerate(solution) if i != 0] - address_num = int(solution.sum()) - - return address_idx, address_num - + + return solution def _get_cache(self, data, max_address_num, require_more_address): pred_res, pred_res_prob, key = data if self.multiple_predictions: - pred_res = _flatten(pred_res) + pred_res = flatten(pred_res) key = tuple(key) if (tuple(pred_res), key) in self.cache_min_address_num: address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), key)] + require_more_address) @@ -95,132 +106,135 @@ class AbducerBase(abc.ABC): else: return self._get_one_candidate(pred_res, pred_res_prob, candidates) return None - + def _set_cache(self, pred_res, key, min_address_num, address_num, candidates): if self.multiple_predictions: - pred_res = _flatten(pred_res) + pred_res = flatten(pred_res) key = tuple(key) self.cache_min_address_num[(tuple(pred_res), key)] = min_address_num self.cache_candidates[(tuple(pred_res), key, address_num)] = candidates - - def abduce(self, data, max_address_num = -1, require_more_address = 0): + def abduce(self, data, max_address_num=-1, require_more_address=0): pred_res, pred_res_prob, key = data if max_address_num == -1: - max_address_num = len(_flatten(pred_res)) - + max_address_num = len(flatten(pred_res)) + if self.cache: candidate = self._get_cache(data, max_address_num, require_more_address) if candidate is not None: return candidate if self.zoopt: - address_idx, address_num = self._zoopt_get_address_idx(pred_res, key, max_address_num) + solution = self.zoopt_get_solution(pred_res, key, max_address_num) + address_idx = [idx for idx, i in enumerate(solution) if i != 0] candidates = self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) + address_num = int(solution.sum()) min_address_num = address_num else: - candidates, min_address_num, address_num = self.kb.abduce_candidates(pred_res, key, max_address_num, require_more_address, self.multiple_predictions) - + candidates, min_address_num, address_num = self.kb.abduce_candidates( + pred_res, key, max_address_num, require_more_address, self.multiple_predictions + ) + candidate = self._get_one_candidate(pred_res, pred_res_prob, candidates) - - + if self.cache: self._set_cache(pred_res, key, min_address_num, address_num, candidates) return candidate - + def abduce_rules(self, pred_res): return self.kb.abduce_rules(pred_res) - - - def batch_abduce(self, Z, Y, max_address_num = -1, require_more_address = 0): + + def batch_abduce(self, Z, Y, max_address_num=-1, require_more_address=0): if self.multiple_predictions: return self.abduce((Z['cls'], Z['prob'], Y), max_address_num, require_more_address) else: - return [ - self.abduce((z, prob, y), max_address_num, require_more_address)\ - for z, prob, y in zip(Z['cls'], Z['prob'], Y) - ] + return [self.abduce((z, prob, y), max_address_num, require_more_address) for z, prob, y in zip(Z['cls'], Z['prob'], Y)] - def __call__(self, Z, Y, max_address_num = -1, require_more_address = 0): + def __call__(self, Z, Y, max_address_num=-1, require_more_address=0): return self.batch_abduce(Z, Y, max_address_num, require_more_address) - + + + + if __name__ == '__main__': prob1 = [[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] prob2 = [[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] - + kb = add_KB() abd = AbducerBase(kb, 'confidence') - res = abd.abduce(([1, 1], prob1, 8), max_address_num = 2, require_more_address = 0) + res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob2, 8), max_address_num = 2, require_more_address = 0) + res = abd.abduce(([1, 1], prob2, 8), max_address_num=2, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob1, 17), max_address_num = 2, require_more_address = 0) + res = abd.abduce(([1, 1], prob1, 17), max_address_num=2, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob1, 17), max_address_num = 1, require_more_address = 0) + res = abd.abduce(([1, 1], prob1, 17), max_address_num=1, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob1, 20), max_address_num = 2, require_more_address = 0) + res = abd.abduce(([1, 1], prob1, 20), max_address_num=2, require_more_address=0) print(res) print() - + kb = add_prolog_KB() abd = AbducerBase(kb, 'confidence') - res = abd.abduce(([1, 1], prob1, 8), max_address_num = 2, require_more_address = 0) + res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob2, 8), max_address_num = 2, require_more_address = 0) + res = abd.abduce(([1, 1], prob2, 8), max_address_num=2, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob1, 17), max_address_num = 2, require_more_address = 0) + res = abd.abduce(([1, 1], prob1, 17), max_address_num=2, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob1, 17), max_address_num = 1, require_more_address = 0) + res = abd.abduce(([1, 1], prob1, 17), max_address_num=1, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob1, 20), max_address_num = 2, require_more_address = 0) + res = abd.abduce(([1, 1], prob1, 20), max_address_num=2, require_more_address=0) print(res) print() - + kb = add_prolog_KB() - abd = AbducerBase(kb, 'confidence', zoopt = True) - res = abd.abduce(([1, 1], prob1, 8), max_address_num = 2, require_more_address = 0) + abd = AbducerBase(kb, 'confidence', zoopt=True) + res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob2, 8), max_address_num = 2, require_more_address = 0) + res = abd.abduce(([1, 1], prob2, 8), max_address_num=2, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob1, 17), max_address_num = 2, require_more_address = 0) + res = abd.abduce(([1, 1], prob1, 17), max_address_num=2, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob1, 17), max_address_num = 1, require_more_address = 0) + res = abd.abduce(([1, 1], prob1, 17), max_address_num=1, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob1, 20), max_address_num = 2, require_more_address = 0) + res = abd.abduce(([1, 1], prob1, 20), max_address_num=2, require_more_address=0) print(res) print() - - kb = HWF_KB(len_list = [1, 3, 5]) + + kb = HWF_KB(len_list=[1, 3, 5]) abd = AbducerBase(kb, 'hamming') - res = abd.abduce((['5', '+', '2'], None, 3), max_address_num = 2, require_more_address = 0) + res = abd.abduce((['5', '+', '2'], None, 3), max_address_num=2, require_more_address=0) print(res) - res = abd.abduce((['5', '+', '2'], None, 64), max_address_num = 3, require_more_address = 0) + res = abd.abduce((['5', '+', '2'], None, 64), max_address_num=3, require_more_address=0) print(res) - res = abd.abduce((['5', '+', '2'], None, 1.67), max_address_num = 3, require_more_address = 0) + res = abd.abduce((['5', '+', '2'], None, 1.67), max_address_num=3, require_more_address=0) print(res) - res = abd.abduce((['5', '8', '8', '8', '8'], None, 3.17), max_address_num = 5, require_more_address = 3) + res = abd.abduce((['5', '8', '8', '8', '8'], None, 3.17), max_address_num=5, require_more_address=3) print(res) print() - + kb = HED_prolog_KB() abd = AbducerBase(kb, zoopt=True, multiple_predictions=True) consist_exs = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 0, '=', 1, 1]] - consist_exs2 = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 1, '=', 1, 1]] # not consistent with rules + consist_exs2 = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 1, '=', 1, 1]] # not consistent with rules inconsist_exs = [[1, '+', 0, '=', 0], [1, '=', 1, '=', 0], [0, '=', 0, '=', 1, 1]] + # inconsist_exs = [[1, '+', 0, '=', 0], ['=', '=', '=', '=', 0], ['=', '=', 0, '=', '=', '=']] rules = ['my_op([0], [0], [1, 1])', 'my_op([1], [1], [0])', 'my_op([1], [0], [0])'] - + print(kb.logic_forward(consist_exs), kb.logic_forward(inconsist_exs)) print(kb.consist_rule(consist_exs, rules), kb.consist_rule(consist_exs2, rules)) print() - + res = abd.abduce((consist_exs, None, [1] * len(consist_exs))) print(res) res = abd.abduce((inconsist_exs, None, [1] * len(consist_exs))) print(res) print() - + abduced_rules = abd.abduce_rules(consist_exs) print(abduced_rules) + From 3d14196107527bb55f5b91ddff064a036cb067ce Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Sat, 10 Dec 2022 22:11:41 +0800 Subject: [PATCH 120/601] Update abducer_base.py --- abducer/abducer_base.py | 118 ++++++++++++++++++++++++++++------------ 1 file changed, 84 insertions(+), 34 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 1e8522d..7b89791 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -26,9 +26,16 @@ import time class AbducerBase(abc.ABC): - def __init__(self, kb, dist_func='confidence', zoopt=False, multiple_predictions=False, cache=True): + def __init__( + self, + kb, + dist_func="confidence", + zoopt=False, + multiple_predictions=False, + cache=True, + ): self.kb = kb - assert dist_func == 'hamming' or dist_func == 'confidence' + assert dist_func == "hamming" or dist_func == "confidence" self.dist_func = dist_func self.zoopt = zoopt self.multiple_predictions = multiple_predictions @@ -39,11 +46,18 @@ class AbducerBase(abc.ABC): self.cache_candidates = {} def _get_cost_list(self, pred_res, pred_res_prob, candidates): - if self.dist_func == 'hamming': + if self.dist_func == "hamming": return hamming_dist(pred_res, candidates) - elif self.dist_func == 'confidence': - mapping = dict(zip(self.kb.pseudo_label_list, list(range(len(self.kb.pseudo_label_list))))) - return confidence_dist(pred_res_prob, [list(map(lambda x: mapping[x], c)) for c in candidates]) + elif self.dist_func == "confidence": + mapping = dict( + zip( + self.kb.pseudo_label_list, + list(range(len(self.kb.pseudo_label_list))), + ) + ) + return confidence_dist( + pred_res_prob, [list(map(lambda x: mapping[x], c)) for c in candidates] + ) def _get_one_candidate(self, pred_res, pred_res_prob, candidates): if len(candidates) == 0: @@ -61,8 +75,12 @@ class AbducerBase(abc.ABC): all_address_flag = reform_idx(solution, pred_res) score = 0 for idx in enumerate(len(pred_res)): - address_idx = [i for i, flag in enumerate(all_address_flag[idx]) if flag != 0] - candidate = self.kb.address_by_idx([pred_res[idx]], key[idx], address_idx, True) + address_idx = [ + i for i, flag in enumerate(all_address_flag[idx]) if flag != 0 + ] + candidate = self.kb.address_by_idx( + [pred_res[idx]], key[idx], address_idx, True + ) if len(candidate) > 0: score += 1 return score @@ -70,7 +88,9 @@ class AbducerBase(abc.ABC): def _zoopt_address_score(self, pred_res, key, sol): if not self.multiple_predictions: address_idx = [idx for idx, i in enumerate(sol.get_x()) if i != 0] - candidates = self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) + candidates = self.kb.address_by_idx( + pred_res, key, address_idx, self.multiple_predictions + ) return 1 if len(candidates) > 0 else 0 else: return self._zoopt_score_multiple(pred_res, key, sol.get_x()) @@ -98,7 +118,11 @@ class AbducerBase(abc.ABC): pred_res = flatten(pred_res) key = tuple(key) if (tuple(pred_res), key) in self.cache_min_address_num: - address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), key)] + require_more_address) + address_num = min( + max_address_num, + self.cache_min_address_num[(tuple(pred_res), key)] + + require_more_address, + ) if (tuple(pred_res), key, address_num) in self.cache_candidates: candidates = self.cache_candidates[(tuple(pred_res), key, address_num)] if self.zoopt: @@ -127,12 +151,18 @@ class AbducerBase(abc.ABC): if self.zoopt: solution = self.zoopt_get_solution(pred_res, key, max_address_num) address_idx = [idx for idx, i in enumerate(solution) if i != 0] - candidates = self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) + candidates = self.kb.address_by_idx( + pred_res, key, address_idx, self.multiple_predictions + ) address_num = int(solution.sum()) min_address_num = address_num else: candidates, min_address_num, address_num = self.kb.abduce_candidates( - pred_res, key, max_address_num, require_more_address, self.multiple_predictions + pred_res, + key, + max_address_num, + require_more_address, + self.multiple_predictions, ) candidate = self._get_one_candidate(pred_res, pred_res_prob, candidates) @@ -147,23 +177,31 @@ class AbducerBase(abc.ABC): def batch_abduce(self, Z, Y, max_address_num=-1, require_more_address=0): if self.multiple_predictions: - return self.abduce((Z['cls'], Z['prob'], Y), max_address_num, require_more_address) + return self.abduce( + (Z["cls"], Z["prob"], Y), max_address_num, require_more_address + ) else: - return [self.abduce((z, prob, y), max_address_num, require_more_address) for z, prob, y in zip(Z['cls'], Z['prob'], Y)] + return [ + self.abduce((z, prob, y), max_address_num, require_more_address) + for z, prob, y in zip(Z["cls"], Z["prob"], Y) + ] def __call__(self, Z, Y, max_address_num=-1, require_more_address=0): return self.batch_abduce(Z, Y, max_address_num, require_more_address) - - - -if __name__ == '__main__': - prob1 = [[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] - prob2 = [[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] +if __name__ == "__main__": + prob1 = [ + [0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], + [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], + ] + prob2 = [ + [0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], + [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], + ] kb = add_KB() - abd = AbducerBase(kb, 'confidence') + abd = AbducerBase(kb, "confidence") res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) print(res) res = abd.abduce(([1, 1], prob2, 8), max_address_num=2, require_more_address=0) @@ -177,7 +215,7 @@ if __name__ == '__main__': print() kb = add_prolog_KB() - abd = AbducerBase(kb, 'confidence') + abd = AbducerBase(kb, "confidence") res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) print(res) res = abd.abduce(([1, 1], prob2, 8), max_address_num=2, require_more_address=0) @@ -191,7 +229,7 @@ if __name__ == '__main__': print() kb = add_prolog_KB() - abd = AbducerBase(kb, 'confidence', zoopt=True) + abd = AbducerBase(kb, "confidence", zoopt=True) res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) print(res) res = abd.abduce(([1, 1], prob2, 8), max_address_num=2, require_more_address=0) @@ -205,24 +243,38 @@ if __name__ == '__main__': print() kb = HWF_KB(len_list=[1, 3, 5]) - abd = AbducerBase(kb, 'hamming') - res = abd.abduce((['5', '+', '2'], None, 3), max_address_num=2, require_more_address=0) + abd = AbducerBase(kb, "hamming") + res = abd.abduce( + (["5", "+", "2"], None, 3), max_address_num=2, require_more_address=0 + ) print(res) - res = abd.abduce((['5', '+', '2'], None, 64), max_address_num=3, require_more_address=0) + res = abd.abduce( + (["5", "+", "2"], None, 64), max_address_num=3, require_more_address=0 + ) print(res) - res = abd.abduce((['5', '+', '2'], None, 1.67), max_address_num=3, require_more_address=0) + res = abd.abduce( + (["5", "+", "2"], None, 1.67), max_address_num=3, require_more_address=0 + ) print(res) - res = abd.abduce((['5', '8', '8', '8', '8'], None, 3.17), max_address_num=5, require_more_address=3) + res = abd.abduce( + (["5", "8", "8", "8", "8"], None, 3.17), + max_address_num=5, + require_more_address=3, + ) print(res) print() kb = HED_prolog_KB() abd = AbducerBase(kb, zoopt=True, multiple_predictions=True) - consist_exs = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 0, '=', 1, 1]] - consist_exs2 = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 1, '=', 1, 1]] # not consistent with rules - inconsist_exs = [[1, '+', 0, '=', 0], [1, '=', 1, '=', 0], [0, '=', 0, '=', 1, 1]] + consist_exs = [[1, "+", 0, "=", 0], [1, "+", 1, "=", 0], [0, "+", 0, "=", 1, 1]] + consist_exs2 = [ + [1, "+", 0, "=", 0], + [1, "+", 1, "=", 0], + [0, "+", 1, "=", 1, 1], + ] # not consistent with rules + inconsist_exs = [[1, "+", 0, "=", 0], [1, "=", 1, "=", 0], [0, "=", 0, "=", 1, 1]] # inconsist_exs = [[1, '+', 0, '=', 0], ['=', '=', '=', '=', 0], ['=', '=', 0, '=', '=', '=']] - rules = ['my_op([0], [0], [1, 1])', 'my_op([1], [1], [0])', 'my_op([1], [0], [0])'] + rules = ["my_op([0], [0], [1, 1])", "my_op([1], [1], [0])", "my_op([1], [0], [0])"] print(kb.logic_forward(consist_exs), kb.logic_forward(inconsist_exs)) print(kb.consist_rule(consist_exs, rules), kb.consist_rule(consist_exs2, rules)) @@ -236,5 +288,3 @@ if __name__ == '__main__': abduced_rules = abd.abduce_rules(consist_exs) print(abduced_rules) - - From 3fdd013dbbfd8111bde48ac0e639c5bff4cfd32a Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Sat, 10 Dec 2022 22:15:48 +0800 Subject: [PATCH 121/601] Change zoopt score for multiple predictions --- abducer/abducer_base.py | 113 +++++++++++----------------------------- 1 file changed, 29 insertions(+), 84 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 7b89791..72884f9 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -26,16 +26,9 @@ import time class AbducerBase(abc.ABC): - def __init__( - self, - kb, - dist_func="confidence", - zoopt=False, - multiple_predictions=False, - cache=True, - ): + def __init__(self, kb, dist_func='confidence', zoopt=False, multiple_predictions=False, cache=True): self.kb = kb - assert dist_func == "hamming" or dist_func == "confidence" + assert dist_func == 'hamming' or dist_func == 'confidence' self.dist_func = dist_func self.zoopt = zoopt self.multiple_predictions = multiple_predictions @@ -46,18 +39,11 @@ class AbducerBase(abc.ABC): self.cache_candidates = {} def _get_cost_list(self, pred_res, pred_res_prob, candidates): - if self.dist_func == "hamming": + if self.dist_func == 'hamming': return hamming_dist(pred_res, candidates) - elif self.dist_func == "confidence": - mapping = dict( - zip( - self.kb.pseudo_label_list, - list(range(len(self.kb.pseudo_label_list))), - ) - ) - return confidence_dist( - pred_res_prob, [list(map(lambda x: mapping[x], c)) for c in candidates] - ) + elif self.dist_func == 'confidence': + mapping = dict(zip(self.kb.pseudo_label_list, list(range(len(self.kb.pseudo_label_list))))) + return confidence_dist(pred_res_prob, [list(map(lambda x: mapping[x], c)) for c in candidates]) def _get_one_candidate(self, pred_res, pred_res_prob, candidates): if len(candidates) == 0: @@ -75,12 +61,8 @@ class AbducerBase(abc.ABC): all_address_flag = reform_idx(solution, pred_res) score = 0 for idx in enumerate(len(pred_res)): - address_idx = [ - i for i, flag in enumerate(all_address_flag[idx]) if flag != 0 - ] - candidate = self.kb.address_by_idx( - [pred_res[idx]], key[idx], address_idx, True - ) + address_idx = [i for i, flag in enumerate(all_address_flag[idx]) if flag != 0] + candidate = self.kb.address_by_idx([pred_res[idx]], key[idx], address_idx, True) if len(candidate) > 0: score += 1 return score @@ -88,9 +70,7 @@ class AbducerBase(abc.ABC): def _zoopt_address_score(self, pred_res, key, sol): if not self.multiple_predictions: address_idx = [idx for idx, i in enumerate(sol.get_x()) if i != 0] - candidates = self.kb.address_by_idx( - pred_res, key, address_idx, self.multiple_predictions - ) + candidates = self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) return 1 if len(candidates) > 0 else 0 else: return self._zoopt_score_multiple(pred_res, key, sol.get_x()) @@ -118,11 +98,7 @@ class AbducerBase(abc.ABC): pred_res = flatten(pred_res) key = tuple(key) if (tuple(pred_res), key) in self.cache_min_address_num: - address_num = min( - max_address_num, - self.cache_min_address_num[(tuple(pred_res), key)] - + require_more_address, - ) + address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), key)] + require_more_address) if (tuple(pred_res), key, address_num) in self.cache_candidates: candidates = self.cache_candidates[(tuple(pred_res), key, address_num)] if self.zoopt: @@ -151,18 +127,12 @@ class AbducerBase(abc.ABC): if self.zoopt: solution = self.zoopt_get_solution(pred_res, key, max_address_num) address_idx = [idx for idx, i in enumerate(solution) if i != 0] - candidates = self.kb.address_by_idx( - pred_res, key, address_idx, self.multiple_predictions - ) + candidates = self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) address_num = int(solution.sum()) min_address_num = address_num else: candidates, min_address_num, address_num = self.kb.abduce_candidates( - pred_res, - key, - max_address_num, - require_more_address, - self.multiple_predictions, + pred_res, key, max_address_num, require_more_address, self.multiple_predictions ) candidate = self._get_one_candidate(pred_res, pred_res_prob, candidates) @@ -177,31 +147,20 @@ class AbducerBase(abc.ABC): def batch_abduce(self, Z, Y, max_address_num=-1, require_more_address=0): if self.multiple_predictions: - return self.abduce( - (Z["cls"], Z["prob"], Y), max_address_num, require_more_address - ) + return self.abduce((Z['cls'], Z['prob'], Y), max_address_num, require_more_address) else: - return [ - self.abduce((z, prob, y), max_address_num, require_more_address) - for z, prob, y in zip(Z["cls"], Z["prob"], Y) - ] + return [self.abduce((z, prob, y), max_address_num, require_more_address) for z, prob, y in zip(Z['cls'], Z['prob'], Y)] def __call__(self, Z, Y, max_address_num=-1, require_more_address=0): return self.batch_abduce(Z, Y, max_address_num, require_more_address) -if __name__ == "__main__": - prob1 = [ - [0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], - [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], - ] - prob2 = [ - [0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], - [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], - ] +if __name__ == '__main__': + prob1 = [[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] + prob2 = [[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] kb = add_KB() - abd = AbducerBase(kb, "confidence") + abd = AbducerBase(kb, 'confidence') res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) print(res) res = abd.abduce(([1, 1], prob2, 8), max_address_num=2, require_more_address=0) @@ -215,7 +174,7 @@ if __name__ == "__main__": print() kb = add_prolog_KB() - abd = AbducerBase(kb, "confidence") + abd = AbducerBase(kb, 'confidence') res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) print(res) res = abd.abduce(([1, 1], prob2, 8), max_address_num=2, require_more_address=0) @@ -229,7 +188,7 @@ if __name__ == "__main__": print() kb = add_prolog_KB() - abd = AbducerBase(kb, "confidence", zoopt=True) + abd = AbducerBase(kb, 'confidence', zoopt=True) res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) print(res) res = abd.abduce(([1, 1], prob2, 8), max_address_num=2, require_more_address=0) @@ -243,38 +202,24 @@ if __name__ == "__main__": print() kb = HWF_KB(len_list=[1, 3, 5]) - abd = AbducerBase(kb, "hamming") - res = abd.abduce( - (["5", "+", "2"], None, 3), max_address_num=2, require_more_address=0 - ) + abd = AbducerBase(kb, 'hamming') + res = abd.abduce((['5', '+', '2'], None, 3), max_address_num=2, require_more_address=0) print(res) - res = abd.abduce( - (["5", "+", "2"], None, 64), max_address_num=3, require_more_address=0 - ) + res = abd.abduce((['5', '+', '2'], None, 64), max_address_num=3, require_more_address=0) print(res) - res = abd.abduce( - (["5", "+", "2"], None, 1.67), max_address_num=3, require_more_address=0 - ) + res = abd.abduce((['5', '+', '2'], None, 1.67), max_address_num=3, require_more_address=0) print(res) - res = abd.abduce( - (["5", "8", "8", "8", "8"], None, 3.17), - max_address_num=5, - require_more_address=3, - ) + res = abd.abduce((['5', '8', '8', '8', '8'], None, 3.17), max_address_num=5, require_more_address=3) print(res) print() kb = HED_prolog_KB() abd = AbducerBase(kb, zoopt=True, multiple_predictions=True) - consist_exs = [[1, "+", 0, "=", 0], [1, "+", 1, "=", 0], [0, "+", 0, "=", 1, 1]] - consist_exs2 = [ - [1, "+", 0, "=", 0], - [1, "+", 1, "=", 0], - [0, "+", 1, "=", 1, 1], - ] # not consistent with rules - inconsist_exs = [[1, "+", 0, "=", 0], [1, "=", 1, "=", 0], [0, "=", 0, "=", 1, 1]] + consist_exs = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 0, '=', 1, 1]] + consist_exs2 = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 1, '=', 1, 1]] # not consistent with rules + inconsist_exs = [[1, '+', 0, '=', 0], [1, '=', 1, '=', 0], [0, '=', 0, '=', 1, 1]] # inconsist_exs = [[1, '+', 0, '=', 0], ['=', '=', '=', '=', 0], ['=', '=', 0, '=', '=', '=']] - rules = ["my_op([0], [0], [1, 1])", "my_op([1], [1], [0])", "my_op([1], [0], [0])"] + rules = ['my_op([0], [0], [1, 1])', 'my_op([1], [1], [0])', 'my_op([1], [0], [0])'] print(kb.logic_forward(consist_exs), kb.logic_forward(inconsist_exs)) print(kb.consist_rule(consist_exs, rules), kb.consist_rule(consist_exs2, rules)) From c3ed82dea85079d20287bc527f246982f1f0e827 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 12 Dec 2022 13:06:34 +0800 Subject: [PATCH 122/601] Update utils.py --- utils/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 742dc03..d4cf947 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -1,11 +1,11 @@ import numpy as np # for multiple predictions, modify from `learn_add.py` -def _flatten(l): +def flatten(l): return [item for sublist in l for item in _flatten(sublist)] if isinstance(l, list) else [l] # for multiple predictions, modify from `learn_add.py` -def _reform_ids(flatten_pred_res, save_pred_res): +def reform_ids(flatten_pred_res, save_pred_res): re = [] i = 0 for e in save_pred_res: @@ -18,12 +18,12 @@ def _reform_ids(flatten_pred_res, save_pred_res): i = i + j return re -def _hamming_dist(A, B): +def hamming_dist(A, B): B = np.array(B) A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) return np.sum(A != B, axis = 1) -def _confidence_dist(A, B): +def confidence_dist(A, B): B = np.array(B) A = np.clip(A, 1e-9, 1) A = np.expand_dims(A, axis=0) From 15192a06c2c75fa4bd3dc1d8ee4518ec81ebd8fe Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 12 Dec 2022 13:08:42 +0800 Subject: [PATCH 123/601] Update utils.py --- utils/utils.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index d4cf947..44ba6a1 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -2,19 +2,19 @@ import numpy as np # for multiple predictions, modify from `learn_add.py` def flatten(l): - return [item for sublist in l for item in _flatten(sublist)] if isinstance(l, list) else [l] + return [item for sublist in l for item in flatten(sublist)] if isinstance(l, list) else [l] # for multiple predictions, modify from `learn_add.py` -def reform_ids(flatten_pred_res, save_pred_res): +def reform_idx(flatten_pred_res, save_pred_res): re = [] i = 0 for e in save_pred_res: j = 0 - ids = [] + idx = [] while j < len(e): - ids.append(flatten_pred_res[i + j]) + idx.append(flatten_pred_res[i + j]) j += 1 - re.append(ids) + re.append(idx) i = i + j return re From 5bd5e02d492626b4935c4beb373a282e43815d22 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 12 Dec 2022 13:09:36 +0800 Subject: [PATCH 124/601] Update kb.py --- abducer/kb.py | 212 +++++++++++++++++++++++++------------------------- 1 file changed, 105 insertions(+), 107 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 9e28283..6e5f0d3 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -1,14 +1,14 @@ # coding: utf-8 -#================================================================# +# ================================================================# # Copyright (C) 2021 LAMDA All rights reserved. -# +# # File Name :kb.py # Author :freecss # Email :karlfreecss@gmail.com # Created Date :2021/06/03 # Description : # -#================================================================# +# ================================================================# from abc import ABC, abstractmethod import bisect @@ -16,11 +16,12 @@ import copy import numpy as np import sys + sys.path.append("..") from collections import defaultdict from itertools import product, combinations -from utils.utils import _flatten, _reform_ids, _hamming_dist +from utils.utils import flatten, reform_idx, hamming_dist from multiprocessing import Pool @@ -28,35 +29,32 @@ import pyswip class KBBase(ABC): - def __init__(self, pseudo_label_list = None): + def __init__(self, pseudo_label_list=None): pass @abstractmethod def logic_forward(self): pass - + @abstractmethod def abduce_candidates(self): pass - - def address(self, address_num, pred_res, key, multiple_predictions = False): + def address(self, address_num, pred_res, key, multiple_predictions=False): new_candidates = [] if not multiple_predictions: address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) else: - address_idx_list = list(combinations(list(range(len(_flatten(pred_res)))), address_num)) - + address_idx_list = list(combinations(list(range(len(flatten(pred_res)))), address_num)) + for address_idx in address_idx_list: candidates = self.address_by_idx(pred_res, key, address_idx, multiple_predictions) new_candidates += candidates return new_candidates - - - - def abduction(self, pred_res, key, max_address_num, require_more_address, multiple_predictions = False): + + def abduction(self, pred_res, key, max_address_num, require_more_address, multiple_predictions=False): candidates = [] - + for address_num in range(len(pred_res) + 1): if address_num == 0: if abs(self.logic_forward(pred_res) - key) <= 1e-3: @@ -64,14 +62,14 @@ class KBBase(ABC): else: new_candidates = self.address(address_num, pred_res, key, multiple_predictions) candidates += new_candidates - + if len(candidates) > 0: min_address_num = address_num break - + if address_num >= max_address_num: return [], 0, 0 - + for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): if address_num > max_address_num: return candidates, min_address_num, address_num - 1 @@ -79,21 +77,19 @@ class KBBase(ABC): candidates += new_candidates return candidates, min_address_num, address_num - - - def __len__(self): pass + class ClsKB(KBBase): - def __init__(self, GKB_flag = False, pseudo_label_list = None, len_list = None): + def __init__(self, GKB_flag=False, pseudo_label_list=None, len_list=None): super().__init__() self.GKB_flag = GKB_flag self.pseudo_label_list = pseudo_label_list self.len_list = len_list self.prolog_flag = False - + if GKB_flag: self.base = {} X, Y = self._get_GKB(self.pseudo_label_list, self.len_list) @@ -102,8 +98,8 @@ class ClsKB(KBBase): else: self.all_address_candidate_dict = {} for address_num in range(max(self.len_list) + 1): - self.all_address_candidate_dict[address_num] = list(product(self.pseudo_label_list, repeat = address_num)) - + self.all_address_candidate_dict[address_num] = list(product(self.pseudo_label_list, repeat=address_num)) + # For parallel version of _get_GKB def _get_XY_list(self, args): pre_x, post_x_it = args[0], args[1] @@ -112,7 +108,7 @@ class ClsKB(KBBase): x = (pre_x,) + post_x y = self.logic_forward(x) if y != np.inf: - XY_list.append((x,y)) + XY_list.append((x, y)) return XY_list # Parallel get GKB @@ -120,7 +116,7 @@ class ClsKB(KBBase): # all_X = [] # for length in len_list: # all_X += list(product(pseudo_label_list, repeat = length)) - + # X, Y = [], [] # for x in all_X: # y = self.logic_forward(x) @@ -132,7 +128,7 @@ class ClsKB(KBBase): for length in len_list: arg_list = [] for pre_x in pseudo_label_list: - post_x_it = product(pseudo_label_list, repeat = length-1) + post_x_it = product(pseudo_label_list, repeat=length - 1) arg_list.append((pre_x, post_x_it)) with Pool(processes=len(arg_list)) as pool: ret_list = pool.map(self._get_XY_list, arg_list) @@ -143,57 +139,54 @@ class ClsKB(KBBase): X.extend(part_X) Y.extend(part_Y) return X, Y - + def logic_forward(self): pass - - def abduce_candidates(self, pred_res, key, max_address_num = -1, require_more_address = 0, multiple_predictions = False): + + def abduce_candidates(self, pred_res, key, max_address_num=-1, require_more_address=0, multiple_predictions=False): if self.GKB_flag: return self.abduce_from_GKB(pred_res, key, max_address_num, require_more_address) else: return self.abduction(pred_res, key, max_address_num, require_more_address, multiple_predictions) - def abduce_from_GKB(self, pred_res, key, max_address_num, require_more_address): if self.base == {} or len(pred_res) not in self.len_list: return [] - + all_candidates = self.base[len(pred_res)][key] - + if len(all_candidates) == 0: candidates = [] min_address_num = 0 address_num = 0 else: - cost_list = _hamming_dist(pred_res, all_candidates) + cost_list = hamming_dist(pred_res, all_candidates) min_address_num = np.min(cost_list) address_num = min(max_address_num, min_address_num + require_more_address) idxs = np.where(cost_list <= address_num)[0] candidates = [all_candidates[idx] for idx in idxs] - + return candidates, min_address_num, address_num - - def address_by_idx(self, pred_res, key, address_idx, multiple_predictions = False): + def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): candidates = [] abduce_c = self.all_address_candidate_dict[len(address_idx)] - + if multiple_predictions: save_pred_res = pred_res - pred_res = _flatten(pred_res) - + pred_res = flatten(pred_res) + for c in abduce_c: candidate = pred_res.copy() for i, idx in enumerate(address_idx): candidate[idx] = c[i] - + if multiple_predictions: - candidate = _reform_ids(candidate, save_pred_res) - - if self.logic_forward(candidate) == key: + candidate = reform_idx(candidate, save_pred_res) + + if self.logic_forward(candidate) == key: candidates.append(candidate) return candidates - def _dict_len(self, dic): if not self.GKB_flag: @@ -209,20 +202,19 @@ class ClsKB(KBBase): class add_KB(ClsKB): - def __init__(self, GKB_flag = False, \ - pseudo_label_list = list(range(10)), \ - len_list = [2]): + def __init__(self, GKB_flag=False, pseudo_label_list=list(range(10)), len_list=[2]): super().__init__(GKB_flag, pseudo_label_list, len_list) - + def logic_forward(self, nums): return sum(nums) - + + class HWF_KB(ClsKB): - def __init__(self, GKB_flag = False, \ - pseudo_label_list = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', 'times', 'div'], \ - len_list = [1, 3, 5, 7]): + def __init__( + self, GKB_flag=False, pseudo_label_list=['1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', 'times', 'div'], len_list=[1, 3, 5, 7] + ): super().__init__(GKB_flag, pseudo_label_list, len_list) - + def valid_candidate(self, formula): if len(formula) % 2 == 0: return False @@ -232,11 +224,25 @@ class HWF_KB(ClsKB): if i % 2 != 0 and formula[i] not in ['+', '-', 'times', 'div']: return False return True - + def logic_forward(self, formula): if not self.valid_candidate(formula): return np.inf - mapping = {'1':'1', '2':'2', '3':'3', '4':'4', '5':'5', '6':'6', '7':'7', '8':'8', '9':'9', '+':'+', '-':'-', 'times':'*', 'div':'/'} + mapping = { + '1': '1', + '2': '2', + '3': '3', + '4': '4', + '5': '5', + '6': '6', + '7': '7', + '8': '8', + '9': '9', + '+': '+', + '-': '-', + 'times': '*', + 'div': '/', + } formula = [mapping[f] for f in formula] return round(eval(''.join(formula)), 2) @@ -246,51 +252,48 @@ class prolog_KB(KBBase): super().__init__() self.pseudo_label_list = pseudo_label_list self.prolog = pyswip.Prolog() - - + def logic_forward(self): pass - + def abduce_candidates(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): return self.abduction(pred_res, key, max_address_num, require_more_address, multiple_predictions) - - - - def address_by_idx(self, pred_res, key, address_idx, multiple_predictions = False): + + def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): candidates = [] # print(address_idx) if not multiple_predictions: query_string = self.get_query_string(pred_res, key, address_idx) else: - query_string = self.get_query_string_need__flatten(pred_res, key, address_idx) - + query_string = self.get_query_string_need_flatten(pred_res, key, address_idx) + if multiple_predictions: save_pred_res = pred_res - pred_res = _flatten(pred_res) + pred_res = flatten(pred_res) abduce_c = [list(z.values()) for z in list(self.prolog.query(query_string))] for c in abduce_c: candidate = pred_res.copy() for i, idx in enumerate(address_idx): candidate[idx] = c[i] - + if multiple_predictions: - candidate = _reform_ids(candidate, save_pred_res) - + candidate = reform_idx(candidate, save_pred_res) + candidates.append(candidate) - return candidates + return candidates + - class add_prolog_KB(prolog_KB): - def __init__(self, pseudo_label_list = list(range(10))): + def __init__(self, pseudo_label_list=list(range(10))): super().__init__(pseudo_label_list) for i in self.pseudo_label_list: self.prolog.assertz("pseudo_label(%s)" % i) self.prolog.assertz("addition(Z1, Z2, Res) :- pseudo_label(Z1), pseudo_label(Z2), Res is Z1+Z2") - + def logic_forward(self, nums): - return list(self.prolog.query("addition(%s, %s, Res)." %(nums[0], nums[1])))[0]['Res'] - + return list(self.prolog.query("addition(%s, %s, Res)." % (nums[0], nums[1])))[0]['Res'] + def get_query_string(self, pred_res, key, address_idx): query_string = "addition(" for idx, i in enumerate(pred_res): @@ -298,51 +301,47 @@ class add_prolog_KB(prolog_KB): query_string += tmp query_string += "%s)." % key return query_string - + class HED_prolog_KB(prolog_KB): - def __init__(self, pseudo_label_list = [0, 1, '+', '=']): + def __init__(self, pseudo_label_list=[0, 1, '+', '=']): super().__init__(pseudo_label_list) self.prolog.consult('./datasets/hed/learn_add.pl') - - # corresponding to `con_sol is not None` in `consistent_score_mapped` within `learn_add.py` + + # corresponding to `con_sol is not None` in `consistent_score_mapped` within `learn_add.py` def logic_forward(self, exs): return len(list(self.prolog.query("abduce_consistent_insts(%s)." % exs))) != 0 - - def get_query_string_need__flatten(self, pred_res, key, address_idx): - # _flatten - _flatten_pred_res = _flatten(pred_res) + def get_query_string_need_flatten(self, pred_res, key, address_idx): + # flatten + flatten_pred_res = flatten(pred_res) # add variables for prolog - for idx in range(len(_flatten_pred_res)): + for idx in range(len(flatten_pred_res)): if idx in address_idx: - _flatten_pred_res[idx] = 'X' + str(idx) - # un_flatten - new_pred_res = _reform_ids(_flatten_pred_res, pred_res) - + flatten_pred_res[idx] = 'X' + str(idx) + # unflatten + new_pred_res = reform_idx(flatten_pred_res, pred_res) + query_string = "abduce_consistent_insts(%s)." % new_pred_res return query_string.replace("'", "").replace("+", "'+'").replace("=", "'='") - - - + def consist_rule(self, exs, rules): - rule_str = "%s" % rules + rule_str = "%s" % rules rule_str = rule_str.replace("'", "") - return len(list(self.prolog.query("consistent_inst_feature(%s, %s)." %(exs, rule_str)))) != 0 - + return len(list(self.prolog.query("consistent_inst_feature(%s, %s)." % (exs, rule_str)))) != 0 + def abduce_rules(self, pred_res): prolog_rules = list(self.prolog.query("consistent_inst_feature(%s, X)." % pred_res))[0]['X'] rules = [] for rule in prolog_rules: rules.append(rule.value) return rules - + # def consist_rules(self, pred_res, rules): - class RegKB(KBBase): - def __init__(self, GKB_flag = False, X = None, Y = None): + def __init__(self, GKB_flag=False, X=None, Y=None): super().__init__() tmp_dict = {} for x, y in zip(X, Y): @@ -357,12 +356,11 @@ class RegKB(KBBase): def valid_candidate(self): pass - + def logic_forward(self): pass - - - def abduce_candidates(self, key, length = None): + + def abduce_candidates(self, key, length=None): if key is None: return self.get_all_candidates() @@ -392,14 +390,15 @@ class RegKB(KBBase): def __len__(self): return sum([sum(len(x) for x in D[0]) for D in self.base.values()]) + import time + if __name__ == "__main__": t1 = time.time() kb = HWF_KB(True) t2 = time.time() - print(t2-t1) - - + print(t2 - t1) + # X = ["1+1", "0+1", "1+0", "2+0", "1+0+1"] # Y = [2, 1, 1, 2, 2] # kb = ClsKB(X, Y) @@ -411,7 +410,7 @@ if __name__ == "__main__": # res = kb.get_candidates(None) # print(res) # print() - + # X = ["1+1", "0+1", "1+0", "2+0", "1+0.5", "0.75+0.75"] # Y = [2, 1, 1, 2, 1.5, 1.5] # kb = RegKB(X, Y) @@ -422,4 +421,3 @@ if __name__ == "__main__": # print(res) # res = kb.get_candidates(None) # print(res) - From 723803b8f2b4a39d96f1bee7d17bdbb9626bec1a Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 12 Dec 2022 15:42:13 +0800 Subject: [PATCH 125/601] Framework for HED dataset (not complete) --- framework_hed.py | 263 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 framework_hed.py diff --git a/framework_hed.py b/framework_hed.py new file mode 100644 index 0000000..1942e5c --- /dev/null +++ b/framework_hed.py @@ -0,0 +1,263 @@ +import numpy as np +from utils.utils import flatten, reform_idx + + +def get_rules_from_data(equations_true): + SAMPLES_PER_RULE = 3 + + select_index = np.random.randint(len(equations_true), size=SAMPLES_PER_RULE) + select_equations = np.array(equations_true)[select_index] + + +def get_consist_idx(exs, abducer): + consistent_ex_idx = [] + label = [] + for idx, e in enumerate(exs): + if abducer.kb.logic_forward([e]): + consistent_ex_idx.append(idx) + label.append(e) + return consistent_ex_idx, label + +def get_label(exs, solution, abducer): + all_address_flag = reform_idx(solution, exs) + consistent_ex_idx = [] + label = [] + for idx, ex in enumerate(exs): + address_idx = [i for i, flag in enumerate(all_address_flag[idx]) if flag != 0] + candidate = abducer.kb.address_by_idx([ex], 1, address_idx, True) + if len(candidate) > 0: + consistent_ex_idx.append(idx) + label.append(candidate[0][0]) + return consistent_ex_idx, label + + +def get_percentage_precision(select_X, consistent_ex_idx, equation_label): + + images = [] + for idx in consistent_ex_idx: + images.append(select_X[idx]) + + ## TODO + model_labels = model.predict(images) + + assert(len(flatten(model_labels)) == len(flatten(equation_label))) + return (flatten(model_labels) == flatten(equation_label)).sum() / len(flatten(model_labels)) + + + + + +def abduce_and_train(model, abducer, train_X_true, select_num): + + select_index = np.random.randint(len(train_X_true), size=select_num) + select_X = train_X_true[select_index] + + + + exs = select_X.predict() + # e.g. when select_num == 10, exs = [[1, '+', 0, '=', 1, 0], [1, '+', 0, '=', 1, 0], [1, '+', 0, '=', 1, 0], [0, '+', 0, '=', 0], [1, '+', 0, '=', 1, 0],\ + # [1, '+', 0, '=', 1, 0], [1, '+', 0, '=', 1, 0], [1, '+', 0, '=', 1, 0], [0, '+', 0, '=', 0], [1, '+', 0, '=', 1, 0]] + + print("This is the model's current label:", exs) + + # 1. Check if it can abduce rules without changing any labels + consistent_ex_idx, equation_label = get_consist_idx(exs) + + + max_abduce_num = 10 + if len(consistent_ex_idx) == 0: + + # 2. Find the possible wrong position in symbols and Abduce the right symbol through logic module + solution = abducer.zoopt_get_solution(exs, [1] * len(exs), max_abduce_num) + consistent_ex_idx, equation_label = get_label(exs, solution, abducer) + + # Still cannot find + if len(consistent_ex_idx) == 0: + return 0, 0 + + + ## TODO: train + # train_pool_X = np.concatenate(select_X[consistent_ex_idx]).reshape( + # -1, h, w, d) + # train_pool_Y = np_utils.to_categorical( + # flatten(exs[consistent_ex_idx]), + # num_classes=len(labels)) # Convert the symbol to network output + # assert (len(train_pool_X) == len(train_pool_Y)) + # print("\nTrain pool size is :", len(train_pool_X)) + # print("Training...") + # base_model.fit(train_pool_X, + # train_pool_Y, + # batch_size=BATCHSIZE, + # epochs=NN_EPOCHS, + # verbose=0) + + # consistent_percentage, batch_label_model_precision = get_percentage_precision( + # base_model, select_equations, consist_re, shape) + + consistent_percentage = len(consistent_ex_idx) / select_num + batch_label_model_precision = get_percentage_precision(exs, consistent_ex_idx, equation_label) + + return consistent_percentage, batch_label_model_precision + +def get_rules(exs): + consistent_ex_idx, equation_label = get_consist_idx(exs) + consist_exs = [] + for idx in consistent_ex_idx: + consist_exs.append(exs[idx]) + if len(consist_exs) == 0: + return None + else: + return abducer.abduce_rule(consist_exs) + + + +def get_rules_from_data(train_X_true, samples_per_rule, logic_output_dim): + rules = [] + for _ in range(logic_output_dim): + while True: + select_index = np.random.randint(len(train_X_true), size=samples_per_rule) + select_X = train_X_true[select_index] + + ## TODO + exs = select_X.predict() + rule = get_rules(exs) + if rule != None: + break + rules.append(rule) + return rules + + +def get_mlp_vector(X, rules): + + ## TODO + exs = np.argmax(model.predict(X)) + + vector = [] + for rule in rules: + if abducer.kb.consist_rule(exs, rule): + vector.append(1) + else: + vector.append(0) + return vector + +def get_mlp_data(X_true, X_false, rules): + mlp_vectors = [] + mlp_labels = [] + for X in X_true: + mlp_vectors.append(get_mlp_vector(X, rules)) + mlp_labels.append(1) + for X in X_false: + mlp_vectors.append(get_mlp_vector(X, rules)) + mlp_labels.append(0) + + return np.array(mlp_vectors), np.array(mlp_labels) + + +def validation(train_X_true, train_X_false, val_X_true, val_X_false): + print("Now checking if we can go to next course") + samples_per_rule = 3 + logic_output_dim = 50 + print("Now checking if we can go to next course") + rules = get_rules_from_data(train_X_true, samples_per_rule, logic_output_dim) + mlp_train_vectors, mlp_train_labels = get_mlp_data(train_X_true, train_X_false, rules) + + index = np.array(list(range(len(mlp_train_labels)))) + np.random.shuffle(index) + mlp_train_vectors = mlp_train_vectors[index] + mlp_train_labels = mlp_train_labels[index] + + best_accuracy = 0 + + #Try three times to find the best mlp + for _ in range(3): + print("Training mlp...") + + ### TODO + # mlp_model = get_mlp_net(logic_output_dim) + # mlp_model.compile(loss='binary_crossentropy', + # optimizer='rmsprop', + # metrics=['accuracy']) + # mlp_model.fit(mlp_train_vectors, + # mlp_train_labels, + # epochs=MLP_EPOCHS, + # batch_size=MLP_BATCHSIZE, + # verbose=0) + #Prepare MLP validation data + + mlp_val_vectors, mlp_val_labels = get_mlp_data(val_X_true, val_X_false, rules) + + ## TODO + #Get MLP validation result + # result = mlp_model.evaluate(mlp_val_vectors, + # mlp_val_labels, + # batch_size=MLP_BATCHSIZE, + # verbose=0) + print("MLP validation result:", result) + accuracy = result[1] + + if accuracy > best_accuracy: + best_accuracy = accuracy + return best_accuracy + + + +def train_HED(model, abducer, train_data, test_data, epochs=50, select_num=10, verbose=-1): + train_X, train_Z, train_Y = train_data + test_X, test_Z, test_Y = test_data + + min_len = 5 + max_len = 8 + + cp_threshold = 0.9 + blmp_threshold = 0.9 + + cnt_threshold = 5 + acc_threshold = 0.86 + + # Start training / for each length of equations + for equation_len in range(min_len, max_len): + + ### TODO: get_data, e.g. + # train_X_true = train_X['True'][equation_len] + # train_X_true.append(train_X['True'][equation_len + 1]) + + + while True: + # Abduce and train NN + consistent_percentage, batch_label_model_precision = abduce_and_train(model, abducer, train_X_true, select_num) + if consistent_percentage == 0: + continue + + # Test if we can use mlp to evaluate + if consistent_percentage >= cp_threshold and batch_label_model_precision >= blmp_threshold: + condition_cnt += 1 + else: + condition_cnt = 0 + # The condition has been satisfied continuously five times + if condition_cnt >= cnt_threshold: + best_accuracy = validation(train_X_true, train_X_false, val_X_true, val_X_false) + + # decide next course or restart + if best_accuracy > acc_threshold: + # Save model and go to next course + ## TODO: model.save_weights() + break + + else: + # Restart current course: reload model + if equation_len == min_len: + ## TODO: model.set_weights(pretrain_model.get_weights()) + model.set_weights() + else: + ## TODO: model.load_weights() + model.load_weights() + print("Failed! Reload model.") + condition_cnt = 0 + + + + return model + + +if __name__ == "__main__": + pass From f33f80737b3aa82db08735c60f2d9056b00523c7 Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Sun, 19 Feb 2023 18:11:58 +0800 Subject: [PATCH 126/601] complete the reproduce of ABL-HED --- .gitignore | 5 +- abducer/abducer_base.py | 115 +++++-- abducer/kb.py | 173 +++++++--- datasets/hed/BK.pl | 83 +++++ datasets/hed/equation_generator.py | 266 +++++++++++++++ datasets/hed/get_hed.py | 130 +++++++ datasets/hed/learn_add.pl | 81 +++++ example.py | 86 +++-- framework_hed.py | 532 ++++++++++++++++++----------- models/basic_model.py | 120 ++++--- models/nn.py | 152 +++++++++ models/wabl_models.py | 75 ++-- utils/plog.py | 47 +-- utils/utils.py | 46 ++- 14 files changed, 1513 insertions(+), 398 deletions(-) create mode 100644 datasets/hed/BK.pl create mode 100644 datasets/hed/equation_generator.py create mode 100644 datasets/hed/get_hed.py create mode 100644 datasets/hed/learn_add.pl create mode 100644 models/nn.py diff --git a/.gitignore b/.gitignore index 8ebaf8d..8ef59e4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ *.pyc /results -raw/ \ No newline at end of file +raw/ +*.jpg +*.png +*.pk \ No newline at end of file diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 72884f9..c0fd102 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -26,9 +26,16 @@ import time class AbducerBase(abc.ABC): - def __init__(self, kb, dist_func='confidence', zoopt=False, multiple_predictions=False, cache=True): + def __init__( + self, + kb, + dist_func="confidence", + zoopt=False, + multiple_predictions=False, + cache=True, + ): self.kb = kb - assert dist_func == 'hamming' or dist_func == 'confidence' + assert dist_func == "hamming" or dist_func == "confidence" self.dist_func = dist_func self.zoopt = zoopt self.multiple_predictions = multiple_predictions @@ -39,11 +46,18 @@ class AbducerBase(abc.ABC): self.cache_candidates = {} def _get_cost_list(self, pred_res, pred_res_prob, candidates): - if self.dist_func == 'hamming': + if self.dist_func == "hamming": return hamming_dist(pred_res, candidates) - elif self.dist_func == 'confidence': - mapping = dict(zip(self.kb.pseudo_label_list, list(range(len(self.kb.pseudo_label_list))))) - return confidence_dist(pred_res_prob, [list(map(lambda x: mapping[x], c)) for c in candidates]) + elif self.dist_func == "confidence": + mapping = dict( + zip( + self.kb.pseudo_label_list, + list(range(len(self.kb.pseudo_label_list))), + ) + ) + return confidence_dist( + pred_res_prob, [list(map(lambda x: mapping[x], c)) for c in candidates] + ) def _get_one_candidate(self, pred_res, pred_res_prob, candidates): if len(candidates) == 0: @@ -60,9 +74,13 @@ class AbducerBase(abc.ABC): def _zoopt_score_multiple(self, pred_res, key, solution): all_address_flag = reform_idx(solution, pred_res) score = 0 - for idx in enumerate(len(pred_res)): - address_idx = [i for i, flag in enumerate(all_address_flag[idx]) if flag != 0] - candidate = self.kb.address_by_idx([pred_res[idx]], key[idx], address_idx, True) + for idx in range(len(pred_res)): + address_idx = [ + i for i, flag in enumerate(all_address_flag[idx]) if flag != 0 + ] + candidate = self.kb.address_by_idx( + [pred_res[idx]], key[idx], address_idx, True + ) if len(candidate) > 0: score += 1 return score @@ -70,7 +88,9 @@ class AbducerBase(abc.ABC): def _zoopt_address_score(self, pred_res, key, sol): if not self.multiple_predictions: address_idx = [idx for idx, i in enumerate(sol.get_x()) if i != 0] - candidates = self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) + candidates = self.kb.address_by_idx( + pred_res, key, address_idx, self.multiple_predictions + ) return 1 if len(candidates) > 0 else 0 else: return self._zoopt_score_multiple(pred_res, key, sol.get_x()) @@ -98,7 +118,11 @@ class AbducerBase(abc.ABC): pred_res = flatten(pred_res) key = tuple(key) if (tuple(pred_res), key) in self.cache_min_address_num: - address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), key)] + require_more_address) + address_num = min( + max_address_num, + self.cache_min_address_num[(tuple(pred_res), key)] + + require_more_address, + ) if (tuple(pred_res), key, address_num) in self.cache_candidates: candidates = self.cache_candidates[(tuple(pred_res), key, address_num)] if self.zoopt: @@ -127,12 +151,18 @@ class AbducerBase(abc.ABC): if self.zoopt: solution = self.zoopt_get_solution(pred_res, key, max_address_num) address_idx = [idx for idx, i in enumerate(solution) if i != 0] - candidates = self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) + candidates = self.kb.address_by_idx( + pred_res, key, address_idx, self.multiple_predictions + ) address_num = int(solution.sum()) min_address_num = address_num else: candidates, min_address_num, address_num = self.kb.abduce_candidates( - pred_res, key, max_address_num, require_more_address, self.multiple_predictions + pred_res, + key, + max_address_num, + require_more_address, + self.multiple_predictions, ) candidate = self._get_one_candidate(pred_res, pred_res_prob, candidates) @@ -147,20 +177,31 @@ class AbducerBase(abc.ABC): def batch_abduce(self, Z, Y, max_address_num=-1, require_more_address=0): if self.multiple_predictions: - return self.abduce((Z['cls'], Z['prob'], Y), max_address_num, require_more_address) + return self.abduce( + (Z["cls"], Z["prob"], Y), max_address_num, require_more_address + ) else: - return [self.abduce((z, prob, y), max_address_num, require_more_address) for z, prob, y in zip(Z['cls'], Z['prob'], Y)] + return [ + self.abduce((z, prob, y), max_address_num, require_more_address) + for z, prob, y in zip(Z["cls"], Z["prob"], Y) + ] def __call__(self, Z, Y, max_address_num=-1, require_more_address=0): return self.batch_abduce(Z, Y, max_address_num, require_more_address) -if __name__ == '__main__': - prob1 = [[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] - prob2 = [[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] +if __name__ == "__main__": + prob1 = [ + [0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], + [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], + ] + prob2 = [ + [0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], + [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], + ] kb = add_KB() - abd = AbducerBase(kb, 'confidence') + abd = AbducerBase(kb, "confidence") res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) print(res) res = abd.abduce(([1, 1], prob2, 8), max_address_num=2, require_more_address=0) @@ -174,7 +215,7 @@ if __name__ == '__main__': print() kb = add_prolog_KB() - abd = AbducerBase(kb, 'confidence') + abd = AbducerBase(kb, "confidence") res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) print(res) res = abd.abduce(([1, 1], prob2, 8), max_address_num=2, require_more_address=0) @@ -188,7 +229,7 @@ if __name__ == '__main__': print() kb = add_prolog_KB() - abd = AbducerBase(kb, 'confidence', zoopt=True) + abd = AbducerBase(kb, "confidence", zoopt=True) res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) print(res) res = abd.abduce(([1, 1], prob2, 8), max_address_num=2, require_more_address=0) @@ -202,24 +243,38 @@ if __name__ == '__main__': print() kb = HWF_KB(len_list=[1, 3, 5]) - abd = AbducerBase(kb, 'hamming') - res = abd.abduce((['5', '+', '2'], None, 3), max_address_num=2, require_more_address=0) + abd = AbducerBase(kb, "hamming") + res = abd.abduce( + (["5", "+", "2"], None, 3), max_address_num=2, require_more_address=0 + ) print(res) - res = abd.abduce((['5', '+', '2'], None, 64), max_address_num=3, require_more_address=0) + res = abd.abduce( + (["5", "+", "2"], None, 64), max_address_num=3, require_more_address=0 + ) print(res) - res = abd.abduce((['5', '+', '2'], None, 1.67), max_address_num=3, require_more_address=0) + res = abd.abduce( + (["5", "+", "2"], None, 1.67), max_address_num=3, require_more_address=0 + ) print(res) - res = abd.abduce((['5', '8', '8', '8', '8'], None, 3.17), max_address_num=5, require_more_address=3) + res = abd.abduce( + (["5", "8", "8", "8", "8"], None, 3.17), + max_address_num=5, + require_more_address=3, + ) print(res) print() kb = HED_prolog_KB() abd = AbducerBase(kb, zoopt=True, multiple_predictions=True) - consist_exs = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 0, '=', 1, 1]] - consist_exs2 = [[1, '+', 0, '=', 0], [1, '+', 1, '=', 0], [0, '+', 1, '=', 1, 1]] # not consistent with rules - inconsist_exs = [[1, '+', 0, '=', 0], [1, '=', 1, '=', 0], [0, '=', 0, '=', 1, 1]] + consist_exs = [[1, "+", 0, "=", 0], [1, "+", 1, "=", 0], [0, "+", 0, "=", 1, 1]] + consist_exs2 = [ + [1, "+", 0, "=", 0], + [1, "+", 1, "=", 0], + [0, "+", 1, "=", 1, 1], + ] # not consistent with rules + inconsist_exs = [[1, "+", 0, "=", 0], [1, "=", 1, "=", 0], [0, "=", 0, "=", 1, 1]] # inconsist_exs = [[1, '+', 0, '=', 0], ['=', '=', '=', '=', 0], ['=', '=', 0, '=', '=', '=']] - rules = ['my_op([0], [0], [1, 1])', 'my_op([1], [1], [0])', 'my_op([1], [0], [0])'] + rules = ["my_op([0], [0], [1, 1])", "my_op([1], [1], [0])", "my_op([1], [0], [0])"] print(kb.logic_forward(consist_exs), kb.logic_forward(inconsist_exs)) print(kb.consist_rule(consist_exs, rules), kb.consist_rule(consist_exs2, rules)) diff --git a/abducer/kb.py b/abducer/kb.py index 6e5f0d3..04a9f68 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -43,16 +43,29 @@ class KBBase(ABC): def address(self, address_num, pred_res, key, multiple_predictions=False): new_candidates = [] if not multiple_predictions: - address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) + address_idx_list = list( + combinations(list(range(len(pred_res))), address_num) + ) else: - address_idx_list = list(combinations(list(range(len(flatten(pred_res)))), address_num)) + address_idx_list = list( + combinations(list(range(len(flatten(pred_res)))), address_num) + ) for address_idx in address_idx_list: - candidates = self.address_by_idx(pred_res, key, address_idx, multiple_predictions) + candidates = self.address_by_idx( + pred_res, key, address_idx, multiple_predictions + ) new_candidates += candidates return new_candidates - def abduction(self, pred_res, key, max_address_num, require_more_address, multiple_predictions=False): + def abduction( + self, + pred_res, + key, + max_address_num, + require_more_address, + multiple_predictions=False, + ): candidates = [] for address_num in range(len(pred_res) + 1): @@ -60,7 +73,9 @@ class KBBase(ABC): if abs(self.logic_forward(pred_res) - key) <= 1e-3: candidates.append(pred_res) else: - new_candidates = self.address(address_num, pred_res, key, multiple_predictions) + new_candidates = self.address( + address_num, pred_res, key, multiple_predictions + ) candidates += new_candidates if len(candidates) > 0: @@ -70,10 +85,14 @@ class KBBase(ABC): if address_num >= max_address_num: return [], 0, 0 - for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): + for address_num in range( + min_address_num + 1, min_address_num + require_more_address + 1 + ): if address_num > max_address_num: return candidates, min_address_num, address_num - 1 - new_candidates = self.address(address_num, pred_res, key, multiple_predictions) + new_candidates = self.address( + address_num, pred_res, key, multiple_predictions + ) candidates += new_candidates return candidates, min_address_num, address_num @@ -98,7 +117,9 @@ class ClsKB(KBBase): else: self.all_address_candidate_dict = {} for address_num in range(max(self.len_list) + 1): - self.all_address_candidate_dict[address_num] = list(product(self.pseudo_label_list, repeat=address_num)) + self.all_address_candidate_dict[address_num] = list( + product(self.pseudo_label_list, repeat=address_num) + ) # For parallel version of _get_GKB def _get_XY_list(self, args): @@ -143,11 +164,26 @@ class ClsKB(KBBase): def logic_forward(self): pass - def abduce_candidates(self, pred_res, key, max_address_num=-1, require_more_address=0, multiple_predictions=False): + def abduce_candidates( + self, + pred_res, + key, + max_address_num=-1, + require_more_address=0, + multiple_predictions=False, + ): if self.GKB_flag: - return self.abduce_from_GKB(pred_res, key, max_address_num, require_more_address) + return self.abduce_from_GKB( + pred_res, key, max_address_num, require_more_address + ) else: - return self.abduction(pred_res, key, max_address_num, require_more_address, multiple_predictions) + return self.abduction( + pred_res, + key, + max_address_num, + require_more_address, + multiple_predictions, + ) def abduce_from_GKB(self, pred_res, key, max_address_num, require_more_address): if self.base == {} or len(pred_res) not in self.len_list: @@ -211,7 +247,24 @@ class add_KB(ClsKB): class HWF_KB(ClsKB): def __init__( - self, GKB_flag=False, pseudo_label_list=['1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', 'times', 'div'], len_list=[1, 3, 5, 7] + self, + GKB_flag=False, + pseudo_label_list=[ + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "+", + "-", + "times", + "div", + ], + len_list=[1, 3, 5, 7], ): super().__init__(GKB_flag, pseudo_label_list, len_list) @@ -219,9 +272,19 @@ class HWF_KB(ClsKB): if len(formula) % 2 == 0: return False for i in range(len(formula)): - if i % 2 == 0 and formula[i] not in ['1', '2', '3', '4', '5', '6', '7', '8', '9']: + if i % 2 == 0 and formula[i] not in [ + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + ]: return False - if i % 2 != 0 and formula[i] not in ['+', '-', 'times', 'div']: + if i % 2 != 0 and formula[i] not in ["+", "-", "times", "div"]: return False return True @@ -229,22 +292,22 @@ class HWF_KB(ClsKB): if not self.valid_candidate(formula): return np.inf mapping = { - '1': '1', - '2': '2', - '3': '3', - '4': '4', - '5': '5', - '6': '6', - '7': '7', - '8': '8', - '9': '9', - '+': '+', - '-': '-', - 'times': '*', - 'div': '/', + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7", + "8": "8", + "9": "9", + "+": "+", + "-": "-", + "times": "*", + "div": "/", } formula = [mapping[f] for f in formula] - return round(eval(''.join(formula)), 2) + return round(eval("".join(formula)), 2) class prolog_KB(KBBase): @@ -256,8 +319,12 @@ class prolog_KB(KBBase): def logic_forward(self): pass - def abduce_candidates(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): - return self.abduction(pred_res, key, max_address_num, require_more_address, multiple_predictions) + def abduce_candidates( + self, pred_res, key, max_address_num, require_more_address, multiple_predictions + ): + return self.abduction( + pred_res, key, max_address_num, require_more_address, multiple_predictions + ) def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): candidates = [] @@ -265,7 +332,9 @@ class prolog_KB(KBBase): if not multiple_predictions: query_string = self.get_query_string(pred_res, key, address_idx) else: - query_string = self.get_query_string_need_flatten(pred_res, key, address_idx) + query_string = self.get_query_string_need_flatten( + pred_res, key, address_idx + ) if multiple_predictions: save_pred_res = pred_res @@ -289,24 +358,28 @@ class add_prolog_KB(prolog_KB): super().__init__(pseudo_label_list) for i in self.pseudo_label_list: self.prolog.assertz("pseudo_label(%s)" % i) - self.prolog.assertz("addition(Z1, Z2, Res) :- pseudo_label(Z1), pseudo_label(Z2), Res is Z1+Z2") + self.prolog.assertz( + "addition(Z1, Z2, Res) :- pseudo_label(Z1), pseudo_label(Z2), Res is Z1+Z2" + ) def logic_forward(self, nums): - return list(self.prolog.query("addition(%s, %s, Res)." % (nums[0], nums[1])))[0]['Res'] + return list(self.prolog.query("addition(%s, %s, Res)." % (nums[0], nums[1])))[ + 0 + ]["Res"] def get_query_string(self, pred_res, key, address_idx): query_string = "addition(" for idx, i in enumerate(pred_res): - tmp = 'Z' + str(idx) + ',' if idx in address_idx else str(i) + ',' + tmp = "Z" + str(idx) + "," if idx in address_idx else str(i) + "," query_string += tmp query_string += "%s)." % key return query_string class HED_prolog_KB(prolog_KB): - def __init__(self, pseudo_label_list=[0, 1, '+', '=']): + def __init__(self, pseudo_label_list=[0, 1, "+", "="]): super().__init__(pseudo_label_list) - self.prolog.consult('./datasets/hed/learn_add.pl') + self.prolog.consult("./datasets/hed/learn_add.pl") # corresponding to `con_sol is not None` in `consistent_score_mapped` within `learn_add.py` def logic_forward(self, exs): @@ -318,7 +391,7 @@ class HED_prolog_KB(prolog_KB): # add variables for prolog for idx in range(len(flatten_pred_res)): if idx in address_idx: - flatten_pred_res[idx] = 'X' + str(idx) + flatten_pred_res[idx] = "X" + str(idx) # unflatten new_pred_res = reform_idx(flatten_pred_res, pred_res) @@ -326,12 +399,30 @@ class HED_prolog_KB(prolog_KB): return query_string.replace("'", "").replace("+", "'+'").replace("=", "'='") def consist_rule(self, exs, rules): - rule_str = "%s" % rules - rule_str = rule_str.replace("'", "") - return len(list(self.prolog.query("consistent_inst_feature(%s, %s)." % (exs, rule_str)))) != 0 + consist = False + for rule in rules: + # print(rule) + if ( + len( + list( + self.prolog.query( + "consistent_inst_feature(%s, [%s])." % (exs, rule) + ) + ) + ) + != 0 + ): + consist = True + break + return consist def abduce_rules(self, pred_res): - prolog_rules = list(self.prolog.query("consistent_inst_feature(%s, X)." % pred_res))[0]['X'] + prolog_result = list( + self.prolog.query("consistent_inst_feature(%s, X)." % pred_res) + ) + if len(prolog_result) == 0: + return None + prolog_rules = prolog_result[0]["X"] rules = [] for rule in prolog_rules: rules.append(rule.value) diff --git a/datasets/hed/BK.pl b/datasets/hed/BK.pl new file mode 100644 index 0000000..441df4e --- /dev/null +++ b/datasets/hed/BK.pl @@ -0,0 +1,83 @@ +:- use_module(library(apply)). +:- use_module(library(lists)). +% :- use_module(library(tabling)). +% :- table valid_rules/2, op_rule/2. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% DCG parser for equations +%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% symbols to be mapped +digit(1). +digit(0). + +% digits +digits([D]) --> [D], { digit(D) }. % empty list [] is not a digit +digits([D | T]) --> [D], !, digits(T), { digit(D) }. +digits(X):- + phrase(digits(X), X). +% More integrity constraints 1: +% This two clauses forbid the first digit to be 0. +% You may uncomment them to prune the search space +% length(X, L), +% (L > 1 -> X \= [0 | _]; true). + +% Equation definition +eq_arg([D]) --> [D], { \+ D == '+', \+ D == '=' }. +eq_arg([D | T]) --> [D], !, eq_arg(T), { \+ D == '+', \+ D == '=' }. +equation(eq(X, Y, Z)) --> + eq_arg(X), [+], eq_arg(Y), [=], eq_arg(Z). +% More integrity constraints 2: +% This clause restricts the length of arguments to be sane, +% You may uncomment them to prune the search space +% { length(X, LX), length(Y, LY), length(Z, LZ), +% LZ =< max(LX, LY) + 1, LZ >= max(LX, LY) }. +parse_eq(List_of_Terms, Eq) :- + phrase(equation(Eq), List_of_Terms). + +%%%%%%%%%%%%%%%%%%%%%% +%% Bit-wise operation +%%%%%%%%%%%%%%%%%%%%%% +% Abductive calculation with given pseudo-labels, abduces pseudo-labels as well as operation rules +calc(Rules, Pseudo) :- + calc([], Rules, Pseudo). +calc(Rules0, Rules1, Pseudo) :- + parse_eq(Pseudo, eq(X,Y,Z)), + bitwise_calc(Rules0, Rules1, X, Y, Z). + +% Bit-wise calculation that handles carrying +bitwise_calc(Rules, Rules1, X, Y, Z) :- + reverse(X, X1), reverse(Y, Y1), reverse(Z, Z1), + bitwise_calc_r(Rules, Rules1, X1, Y1, Z1), + maplist(digits, [X,Y,Z]). +bitwise_calc_r(Rs, Rs, [], Y, Y). +bitwise_calc_r(Rs, Rs, X, [], X). +bitwise_calc_r(Rules, Rules1, [D1 | X], [D2 | Y], [D3 | Z]) :- + abduce_op_rule(my_op([D1],[D2],Sum), Rules, Rules2), + ((Sum = [D3], Carry = []); (Sum = [C, D3], Carry = [C])), + bitwise_calc_r(Rules2, Rules3, X, Carry, X_carried), + bitwise_calc_r(Rules3, Rules1, X_carried, Y, Z). + +%%%%%%%%%%%%%%%%%%%%%%%%% +% Abduce operation rules +%%%%%%%%%%%%%%%%%%%%%%%%% +% Get an existed rule +abduce_op_rule(R, Rules, Rules) :- + member(R, Rules). +% Add a new rule +abduce_op_rule(R, Rules, [R|Rules]) :- + op_rule(R), + valid_rules(Rules, R). + +% Integrity Constraints +valid_rules([], _). +valid_rules([my_op([X1],[Y1],_)|Rs], my_op([X],[Y],Z)) :- + op_rule(my_op([X],[Y],Z)), + [X,Y] \= [X1,Y1], + [X,Y] \= [Y1,X1], + valid_rules(Rs, my_op([X],[Y],Z)). +valid_rules([my_op([Y],[X],Z)|Rs], my_op([X],[Y],Z)) :- + X \= Y, + valid_rules(Rs, my_op([X],[Y],Z)). + +op_rule(my_op([X],[Y],[Z])) :- digit(X), digit(Y), digit(Z). +op_rule(my_op([X],[Y],[Z1,Z2])) :- digit(X), digit(Y), digits([Z1,Z2]). diff --git a/datasets/hed/equation_generator.py b/datasets/hed/equation_generator.py new file mode 100644 index 0000000..3cf735b --- /dev/null +++ b/datasets/hed/equation_generator.py @@ -0,0 +1,266 @@ +import os +import itertools +import random +import numpy as np +from PIL import Image +import pickle + + +def get_sign_path_list(data_dir, sign_names): + sign_num = len(sign_names) + index_dict = dict(zip(sign_names, list(range(sign_num)))) + ret = [[] for _ in range(sign_num)] + for path in os.listdir(data_dir): + if path in sign_names: + index = index_dict[path] + sign_path = os.path.join(data_dir, path) + for p in os.listdir(sign_path): + ret[index].append(os.path.join(sign_path, p)) + return ret + + +def split_pool_by_rate(pools, rate, seed=None): + if seed is not None: + random.seed(seed) + ret1 = [] + ret2 = [] + for pool in pools: + random.shuffle(pool) + num = int(len(pool) * rate) + ret1.append(pool[:num]) + ret2.append(pool[num:]) + return ret1, ret2 + + +def int_to_system_form(num, system_num): + if num is 0: + return "0" + ret = "" + while num > 0: + ret += str(num % system_num) + num //= system_num + return ret[::-1] + + +def generator_equations( + left_opt_len, right_opt_len, res_opt_len, system_num, label, generate_type +): + expr_len = left_opt_len + right_opt_len + num_list = "".join([str(i) for i in range(system_num)]) + ret = [] + if generate_type == "all": + candidates = itertools.product(num_list, repeat=expr_len) + else: + candidates = ["".join(random.sample(["0", "1"] * expr_len, expr_len))] + random.shuffle(candidates) + for nums in candidates: + left_num = "".join(nums[:left_opt_len]) + right_num = "".join(nums[left_opt_len:]) + left_value = int(left_num, system_num) + right_value = int(right_num, system_num) + result_value = left_value + right_value + if label == "negative": + result_value += random.randint(-result_value, result_value) + if left_value + right_value == result_value: + continue + result_num = int_to_system_form(result_value, system_num) + # leading zeros + if res_opt_len != len(result_num): + continue + if (left_opt_len > 1 and left_num[0] == "0") or ( + right_opt_len > 1 and right_num[0] == "0" + ): + continue + + # add leading zeros + if res_opt_len < len(result_num): + continue + while len(result_num) < res_opt_len: + result_num = "0" + result_num + # continue + ret.append( + left_num + "+" + right_num + "=" + result_num + ) # current only consider '+' and '=' + # print(ret[-1]) + return ret + + +def generator_equation_by_len(equation_len, system_num=2, label=0, require_num=1): + generate_type = "one" + ret = [] + equation_sign_num = 2 # '+' and '=' + while len(ret) < require_num: + left_opt_len = random.randint(1, equation_len - 1 - equation_sign_num) + right_opt_len = random.randint( + 1, equation_len - left_opt_len - equation_sign_num + ) + res_opt_len = equation_len - left_opt_len - right_opt_len - equation_sign_num + ret.extend( + generator_equations( + left_opt_len, + right_opt_len, + res_opt_len, + system_num, + label, + generate_type, + ) + ) + return ret + + +def generator_equations_by_len( + equation_len, system_num=2, label=0, repeat_times=1, keep=1, generate_type="all" +): + ret = [] + equation_sign_num = 2 # '+' and '=' + for left_opt_len in range(1, equation_len - (2 + equation_sign_num) + 1): + for right_opt_len in range( + 1, equation_len - left_opt_len - (1 + equation_sign_num) + 1 + ): + res_opt_len = ( + equation_len - left_opt_len - right_opt_len - equation_sign_num + ) + for i in range(repeat_times): # generate more equations + if random.random() > keep ** (equation_len): + continue + ret.extend( + generator_equations( + left_opt_len, + right_opt_len, + res_opt_len, + system_num, + label, + generate_type, + ) + ) + return ret + + +def generator_equations_by_max_len( + max_equation_len, + system_num=2, + label=0, + repeat_times=1, + keep=1, + generate_type="all", + num_per_len=None, +): + ret = [] + equation_sign_num = 2 # '+' and '=' + for equation_len in range(3 + equation_sign_num, max_equation_len + 1): + if num_per_len is None: + ret.extend( + generator_equations_by_len( + equation_len, system_num, label, repeat_times, keep, generate_type + ) + ) + else: + ret.extend( + generator_equation_by_len( + equation_len, system_num, label, require_num=num_per_len + ) + ) + return ret + + +def generator_equation_images(image_pools, equations, signs, shape, seed, is_color): + if seed is not None: + random.seed(seed) + ret = [] + sign_num = len(signs) + sign_index_dict = dict(zip(signs, list(range(sign_num)))) + for equation in equations: + data = [] + for sign in equation: + index = sign_index_dict[sign] + pick = random.randint(0, len(image_pools[index]) - 1) + if is_color: + image = ( + Image.open(image_pools[index][pick]).convert("RGB").resize(shape) + ) + else: + image = Image.open(image_pools[index][pick]).convert("I").resize(shape) + image_array = np.array(image) + image_array = (image_array - 127) * (1.0 / 128) + data.append(image_array) + ret.append(np.array(data)) + return ret + + +def get_equation_std_data( + data_dir, + sign_dir_lists, + sign_output_lists, + shape=(28, 28), + train_max_equation_len=10, + test_max_equation_len=10, + system_num=2, + tmp_file_prev=None, + seed=None, + train_num_per_len=10, + test_num_per_len=10, + is_color=False, +): + tmp_file = "" + if tmp_file_prev is not None: + tmp_file = "%s_train_len_%d_test_len_%d_sys_%d_.pk" % ( + tmp_file_prev, + train_max_equation_len, + test_max_equation_len, + system_num, + ) + if os.path.exists(tmp_file): + return pickle.load(open(tmp_file, "rb")) + + image_pools = get_sign_path_list(data_dir, sign_dir_lists) + train_pool, test_pool = split_pool_by_rate(image_pools, 0.8, seed) + + ret = {} + for label in ["positive", "negative"]: + print("Generating equations.") + train_equations = generator_equations_by_max_len( + train_max_equation_len, system_num, label, num_per_len=train_num_per_len + ) + test_equations = generator_equations_by_max_len( + test_max_equation_len, system_num, label, num_per_len=test_num_per_len + ) + print(train_equations) + print(test_equations) + print("Generated equations.") + print("Generating equation image data.") + ret["train:%s" % (label)] = generator_equation_images( + train_pool, train_equations, sign_output_lists, shape, seed, is_color + ) + ret["test:%s" % (label)] = generator_equation_images( + test_pool, test_equations, sign_output_lists, shape, seed, is_color + ) + print("Generated equation image data.") + + if tmp_file_prev is not None: + pickle.dump(ret, open(tmp_file, "wb")) + return ret + + +if __name__ == "__main__": + data_dirs = [ + "./dataset/mnist_images", + "./dataset/random_images", + ] # , "../dataset/cifar10_images"] + tmp_file_prevs = [ + "mnist_equation_data", + "random_equation_data", + ] # , "cifar10_equation_data"] + for data_dir, tmp_file_prev in zip(data_dirs, tmp_file_prevs): + data = get_equation_std_data( + data_dir=data_dir, + sign_dir_lists=["0", "1", "10", "11"], + sign_output_lists=["0", "1", "+", "="], + shape=(28, 28), + train_max_equation_len=26, + test_max_equation_len=26, + system_num=2, + tmp_file_prev=tmp_file_prev, + train_num_per_len=300, + test_num_per_len=300, + is_color=False, + ) diff --git a/datasets/hed/get_hed.py b/datasets/hed/get_hed.py new file mode 100644 index 0000000..8b61b62 --- /dev/null +++ b/datasets/hed/get_hed.py @@ -0,0 +1,130 @@ +import os +import cv2 +import torch +import torchvision +import pickle +import numpy as np +import random +from collections import defaultdict +from torch.utils.data import Dataset +from torchvision.transforms import transforms + + +def get_data(img_dataset, train): + transform = transforms.Compose([transforms.ToTensor()]) + X = [] + Y = [] + if train: + positive = img_dataset["train:positive"] + negative = img_dataset["train:negative"] + else: + positive = img_dataset["test:positive"] + negative = img_dataset["test:negative"] + + for equation in positive: + equation = equation.astype(np.float32) + img_list = np.vsplit(equation, equation.shape[0]) + X.append(img_list) + Y.append(1) + + for equation in negative: + equation = equation.astype(np.float32) + img_list = np.vsplit(equation, equation.shape[0]) + X.append(img_list) + Y.append(0) + + return X, None, Y + + +def get_pretrain_data(labels, image_size=(28, 28, 1)): + transform = transforms.Compose([transforms.ToTensor()]) + X = [] + for label in labels: + label_path = os.path.join( + "./datasets/hed/dataset/mnist_images", label + ) + img_path_list = os.listdir(label_path) + for img_path in img_path_list: + img = cv2.imread( + os.path.join(label_path, img_path), cv2.IMREAD_GRAYSCALE + ) + img = cv2.resize(img, (image_size[1], image_size[0])) + X.append(np.array(img, dtype=np.float32)) + + X = [((img[:, :, np.newaxis] - 127) / 128.0) for img in X] + Y = [img.copy().reshape(image_size[0] * image_size[1] * image_size[2]) for img in X] + + X = [transform(img) for img in X] + return X, Y + + +# def get_pretrain_data(train_data, image_size=(28, 28, 1)): +# X = [] +# for label in [0, 1]: +# for _, equation_list in train_data[label].items(): +# for equation in equation_list: +# X = X + equation + +# X = np.array(X) +# index = np.array(list(range(len(X)))) +# np.random.shuffle(index) +# X = X[index] + +# X = [img for img in X] +# Y = [img.copy().reshape(image_size[0] * image_size[1] * image_size[2]) for img in X] + +# return X, Y + + +def divide_equations_by_len(equations, labels): + equations_by_len = {1: defaultdict(list), 0: defaultdict(list)} + for i, equation in enumerate(equations): + equations_by_len[labels[i]][len(equation)].append(equation) + return equations_by_len + + +def split_equation(equations_by_len, prop_train, prop_val): + """ + Split the equations in each length to training and validation data according to the proportion + """ + train_equations_by_len = {1: dict(), 0: dict()} + val_equations_by_len = {1: dict(), 0: dict()} + + for label in range(2): + for equation_len, equations in equations_by_len[label].items(): + random.shuffle(equations) + train_equations_by_len[label][equation_len] = equations[ + : len(equations) // (prop_train + prop_val) * prop_train + ] + val_equations_by_len[label][equation_len] = equations[ + len(equations) // (prop_train + prop_val) * prop_train : + ] + + return train_equations_by_len, val_equations_by_len + + +def get_hed(dataset="mnist", train=True): + + if dataset == "mnist": + with open( + "./datasets/hed/mnist_equation_data_train_len_26_test_len_26_sys_2_.pk", + "rb", + ) as f: + img_dataset = pickle.load(f) + elif dataset == "random": + with open( + "./datasets/hed/random_equation_data_train_len_26_test_len_26_sys_2_.pk", + "rb", + ) as f: + img_dataset = pickle.load(f) + else: + raise Exception("Undefined dataset") + + X, _, Y = get_data(img_dataset, train) + equations_by_len = divide_equations_by_len(X, Y) + + return equations_by_len + + +if __name__ == "__main__": + get_hed() diff --git a/datasets/hed/learn_add.pl b/datasets/hed/learn_add.pl new file mode 100644 index 0000000..af1d6bb --- /dev/null +++ b/datasets/hed/learn_add.pl @@ -0,0 +1,81 @@ +:- ensure_loaded(['BK.pl']). +:- thread_setconcurrency(_, 8). +:- use_module(library(thread)). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% For propositionalisation +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +eval_inst_feature(Ex, Feature):- + eval_eq(Ex, Feature). + +%% Evaluate instance given feature +eval_eq(Ex, Feature):- + parse_eq(Ex, eq(X,Y,Z)), + bitwise_calc(Feature,_,X,Y,Z), !. + +%%%%%%%%%%%%%% +%% Abduction +%%%%%%%%%%%%%% +% Make abduction when given examples that have been interpreted as pseudo-labels +abduce(Exs, Delta_C) :- + abduce(Exs, [], Delta_C). +abduce([], Delta_C, Delta_C). +abduce([E|Exs], Delta_C0, Delta_C1) :- + calc(Delta_C0, Delta_C2, E), + abduce(Exs, Delta_C2, Delta_C1). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Abduce pseudo-labels only +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +abduce_consistent_insts(Exs):- + abduce(Exs, _), !. +% (Experimental) Uncomment to use parallel abduction +% abduce_consistent_exs_concurrent(Exs), !. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Abduce Delta_C given pseudo-labels +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +consistent_inst_feature(Exs, Delta_C):- + abduce(Exs, Delta_C), !. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% (Experimental) Parallel abduction +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +abduce_consistent_exs_concurrent(Exs) :- + % Split the current data batch into grounding examples and variable examples (which need to be revised) + split_exs(Exs, Ground_Exs, Var_Exs), + % Find the simplest Delta_C for grounding examples. + abduce(Ground_Exs, Ground_Delta_C), !, + % Extend Ground Delta_C into all possible variations + extend_op_rule(Ground_Delta_C, Possible_Deltas), + % Concurrently abduce the variable examples + maplist(append([abduce2, Var_Exs, Ground_Exs]), [[Possible_Deltas]], Call_List), + maplist(=.., Goals, Call_List), + % writeln(Goals), + first_solution(Var_Exs, Goals, [local(inf)]). + +split_exs([],[],[]). +split_exs([E | Exs], [E | G_Exs], V_Exs):- + ground(E), !, + split_exs(Exs, G_Exs, V_Exs). +split_exs([E | Exs], G_Exs, [E | V_Exs]):- + split_exs(Exs, G_Exs, V_Exs). + +:- table extend_op_rule/2. + +extend_op_rule(Rules, Rules) :- + length(Rules, 4). +extend_op_rule(Rules, Ext) :- + op_rule(R), + valid_rules(Rules, R), + extend_op_rule([R|Rules], Ext). + +% abduction without learning new Delta_C (Because they have been extended!) +abduce2([], _, _). +abduce2([E|Exs], Ground_Exs, Delta_C) :- + % abduce by finding ground examples + member(E, Ground_Exs), + abduce2(Exs, Ground_Exs, Delta_C). +abduce2([E|Exs], Ground_Exs, Delta_C) :- + eval_inst_feature(E, Delta_C), + abduce2(Exs, Ground_Exs, Delta_C). diff --git a/example.py b/example.py index 7ceaeff..795d455 100644 --- a/example.py +++ b/example.py @@ -1,60 +1,102 @@ # coding: utf-8 -#================================================================# +# ================================================================# # Copyright (C) 2021 Freecss All rights reserved. -# +# # File Name :share_example.py # Author :freecss # Email :karlfreecss@gmail.com # Created Date :2021/06/07 # Description : # -#================================================================# +# ================================================================# -from utils.plog import logger -import framework +from utils.plog import logger, INFO +import framework_hed import torch.nn as nn import torch -from models.lenet5 import LeNet5, SymbolNet -from models.basic_model import BasicModel + +from models.nn import LeNet5, SymbolNet, SymbolNetAutoencoder +from models.basic_model import BasicModel, BasicDataset from models.wabl_models import WABLBasicModel from multiprocessing import Pool import os from abducer.abducer_base import AbducerBase -from abducer.kb import add_KB, hwf_KB +from abducer.kb import add_KB, HWF_KB, HED_prolog_KB from datasets.mnist_add.get_mnist_add import get_mnist_add from datasets.hwf.get_hwf import get_hwf +from datasets.hed.get_hed import get_hed, get_pretrain_data, split_equation + def run_test(): # kb = add_KB(True) - kb = hwf_KB(True) - abducer = AbducerBase(kb) + + # kb = hwf_KB(True) + # abducer = AbducerBase(kb) + + kb = HED_prolog_KB() + abducer = AbducerBase(kb, zoopt=True, multiple_predictions=True) recorder = logger() - # train_X, train_Z, train_Y = get_mnist_add(train = True, get_pseudo_label = True) - # test_X, test_Z, test_Y = get_mnist_add(train = False, get_pseudo_label = True) - - train_data = get_hwf(train = True, get_pseudo_label = True) - test_data = get_hwf(train = False, get_pseudo_label = True) + # train_X, train_Z, train_Y = get_mnist_add(train=True, get_pseudo_label=True) + # test_X, test_Z, test_Y = get_mnist_add(train=False, get_pseudo_label=True) + + # train_data = get_hwf(train=True, get_pseudo_label=True) + # test_data = get_hwf(train=False, get_pseudo_label=True) + + total_train_data = get_hed(train=True) + train_data, val_data = split_equation(total_train_data, 3, 1) + test_data = get_hed(train=False) # cls = LeNet5(num_classes=len(kb.pseudo_label_list), image_size=(train_data[0][0][0].shape[1:])) + cls_autoencoder = SymbolNetAutoencoder(num_classes=len(kb.pseudo_label_list)) cls = SymbolNet(num_classes=len(kb.pseudo_label_list)) - + + if not os.path.exists("./weights/pretrain_weights.pth"): + pretrain_data_X, pretrain_data_Y = get_pretrain_data(["0", "1", "10", "11"]) + pretrain_data = BasicDataset(pretrain_data_X, pretrain_data_Y) + pretrain_data_loader = torch.utils.data.DataLoader( + pretrain_data, + batch_size=64, + shuffle=True, + ) + framework_hed.pretrain(cls_autoencoder, pretrain_data_loader, recorder) + torch.save( + cls_autoencoder.base_model.state_dict(), "./weights/pretrain_weights.pth" + ) + cls.load_state_dict(torch.load("./weights/pretrain_weights.pth")) + criterion = nn.CrossEntropyLoss() - optimizer = torch.optim.Adam(cls.parameters(), lr=0.001, betas=(0.9, 0.99)) + optimizer = torch.optim.RMSprop( + cls.parameters(), lr=0.001, alpha=0.9, weight_decay=1e-6 + ) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - - base_model = BasicModel(cls, criterion, optimizer, device, save_interval=1, save_dir=recorder.save_dir, num_epochs=1, recorder=recorder) + + base_model = BasicModel( + cls, + criterion, + optimizer, + device, + save_interval=1, + save_dir=recorder.save_dir, + batch_size=32, + num_epochs=10, + recorder=recorder, + ) + model = WABLBasicModel(base_model, kb.pseudo_label_list) - res = framework.train(model, abducer, train_data, test_data, sample_num = 10000, verbose = 1) - recorder.print(res) - + res = framework_hed.train_with_rule( + model, abducer, train_data, val_data, recorder=recorder + ) + INFO(res) + recorder.dump() return True + if __name__ == "__main__": run_test() diff --git a/framework_hed.py b/framework_hed.py index 1942e5c..04b41b8 100644 --- a/framework_hed.py +++ b/framework_hed.py @@ -1,261 +1,395 @@ +# coding: utf-8 +# ================================================================# +# Copyright (C) 2021 Freecss All rights reserved. +# +# File Name :framework.py +# Author :freecss +# Email :karlfreecss@gmail.com +# Created Date :2021/06/07 +# Description : +# +# ================================================================# + +import pickle as pk + import numpy as np -from utils.utils import flatten, reform_idx - - -def get_rules_from_data(equations_true): - SAMPLES_PER_RULE = 3 - - select_index = np.random.randint(len(equations_true), size=SAMPLES_PER_RULE) - select_equations = np.array(equations_true)[select_index] - - -def get_consist_idx(exs, abducer): - consistent_ex_idx = [] - label = [] - for idx, e in enumerate(exs): - if abducer.kb.logic_forward([e]): - consistent_ex_idx.append(idx) - label.append(e) - return consistent_ex_idx, label - -def get_label(exs, solution, abducer): - all_address_flag = reform_idx(solution, exs) - consistent_ex_idx = [] - label = [] - for idx, ex in enumerate(exs): - address_idx = [i for i, flag in enumerate(all_address_flag[idx]) if flag != 0] - candidate = abducer.kb.address_by_idx([ex], 1, address_idx, True) - if len(candidate) > 0: - consistent_ex_idx.append(idx) - label.append(candidate[0][0]) - return consistent_ex_idx, label - - -def get_percentage_precision(select_X, consistent_ex_idx, equation_label): - - images = [] - for idx in consistent_ex_idx: - images.append(select_X[idx]) - - ## TODO - model_labels = model.predict(images) - - assert(len(flatten(model_labels)) == len(flatten(equation_label))) - return (flatten(model_labels) == flatten(equation_label)).sum() / len(flatten(model_labels)) - - - - -def abduce_and_train(model, abducer, train_X_true, select_num): +import random + +random_seed = random.randint(0, 10000) +print("Selected random seed is : ", random_seed) +np.random.seed(random_seed) +random.seed(random_seed) + +from models.nn import MLP +from models.basic_model import BasicModel, BasicDataset +import torch.nn as nn +import torch + +from utils.plog import INFO, DEBUG, clocker +from utils.utils import flatten, reform_idx, block_sample + +from sklearn.tree import DecisionTreeClassifier + + +def result_statistics(pred_Z, Z, Y, logic_forward, char_acc_flag): + result = {} + if char_acc_flag: + char_acc_num = 0 + char_num = 0 + for pred_z, z in zip(pred_Z, Z): + char_num += len(z) + for zidx in range(len(z)): + if pred_z[zidx] == z[zidx]: + char_acc_num += 1 + char_acc = char_acc_num / char_num + result["Character level accuracy"] = char_acc + + abl_acc_num = 0 + for pred_z, y in zip(pred_Z, Y): + if logic_forward(pred_z) == y: + abl_acc_num += 1 + abl_acc = abl_acc_num / len(Y) + result["ABL accuracy"] = abl_acc + + return result + + +def filter_data(X, abduced_Z): + finetune_Z = [] + finetune_X = [] + for abduced_x, abduced_z in zip(X, abduced_Z): + if abduced_z is not []: + finetune_X.append(abduced_x) + finetune_Z.append(abduced_z) + return finetune_X, finetune_Z + + +def pretrain(net, pretrain_data_loader, recorder): + INFO("Pretrain Start") + + criterion = nn.MSELoss() + optimizer = torch.optim.RMSprop( + net.parameters(), lr=0.001, alpha=0.9, weight_decay=1e-6 + ) + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + pretrain_model = BasicModel( + net, + criterion, + optimizer, + device, + save_interval=1, + save_dir=recorder.save_dir, + num_epochs=10, + recorder=recorder, + ) + + pretrain_model.fit(pretrain_data_loader) + + +def get_char_acc(model, X, consistent_pred_res): + pred_res = flatten(model.predict(X)["cls"]) + assert len(pred_res) == len(flatten(consistent_pred_res)) + return sum( + [ + pred_res[idx] == flatten(consistent_pred_res)[idx] + for idx in range(len(pred_res)) + ] + ) / len(pred_res) + + +def gen_mappings(chars, symbs): + n_char = len(chars) + n_symbs = len(symbs) + if n_char != n_symbs: + INFO("Characters and symbols size dosen't match.") + return + from itertools import permutations + + mappings = [] + perms = permutations(symbs) + for p in perms: + mappings.append(dict(zip(chars, list(p)))) + return mappings + + +def map_res(original_pred_res, m): + pred_res = [[m[symbol] for symbol in formula] for formula in original_pred_res] + return pred_res + - select_index = np.random.randint(len(train_X_true), size=select_num) - select_X = train_X_true[select_index] - - - - exs = select_X.predict() - # e.g. when select_num == 10, exs = [[1, '+', 0, '=', 1, 0], [1, '+', 0, '=', 1, 0], [1, '+', 0, '=', 1, 0], [0, '+', 0, '=', 0], [1, '+', 0, '=', 1, 0],\ - # [1, '+', 0, '=', 1, 0], [1, '+', 0, '=', 1, 0], [1, '+', 0, '=', 1, 0], [0, '+', 0, '=', 0], [1, '+', 0, '=', 1, 0]] - - print("This is the model's current label:", exs) - - # 1. Check if it can abduce rules without changing any labels - consistent_ex_idx, equation_label = get_consist_idx(exs) - - - max_abduce_num = 10 - if len(consistent_ex_idx) == 0: - - # 2. Find the possible wrong position in symbols and Abduce the right symbol through logic module - solution = abducer.zoopt_get_solution(exs, [1] * len(exs), max_abduce_num) - consistent_ex_idx, equation_label = get_label(exs, solution, abducer) - - # Still cannot find - if len(consistent_ex_idx) == 0: - return 0, 0 - - - ## TODO: train - # train_pool_X = np.concatenate(select_X[consistent_ex_idx]).reshape( - # -1, h, w, d) - # train_pool_Y = np_utils.to_categorical( - # flatten(exs[consistent_ex_idx]), - # num_classes=len(labels)) # Convert the symbol to network output - # assert (len(train_pool_X) == len(train_pool_Y)) - # print("\nTrain pool size is :", len(train_pool_X)) - # print("Training...") - # base_model.fit(train_pool_X, - # train_pool_Y, - # batch_size=BATCHSIZE, - # epochs=NN_EPOCHS, - # verbose=0) - - # consistent_percentage, batch_label_model_precision = get_percentage_precision( - # base_model, select_equations, consist_re, shape) - - consistent_percentage = len(consistent_ex_idx) / select_num - batch_label_model_precision = get_percentage_precision(exs, consistent_ex_idx, equation_label) - - return consistent_percentage, batch_label_model_precision - -def get_rules(exs): - consistent_ex_idx, equation_label = get_consist_idx(exs) - consist_exs = [] - for idx in consistent_ex_idx: - consist_exs.append(exs[idx]) - if len(consist_exs) == 0: - return None - else: - return abducer.abduce_rule(consist_exs) - - - -def get_rules_from_data(train_X_true, samples_per_rule, logic_output_dim): +def abduce_and_train(model, abducer, train_X_true, select_num): + select_idx = np.random.randint(len(train_X_true), size=select_num) + X = [] + for idx in select_idx: + X.append(train_X_true[idx]) + + pred_res = model.predict(X)["cls"] + + maps = gen_mappings(["+", "=", 0, 1], ["+", "=", 0, 1]) + + consistent_idx = [] + consistent_pred_res = [] + + import copy + + original_pred_res = copy.deepcopy(pred_res) + mapping = None + + for m in maps: + pred_res = map_res(original_pred_res, m) + remapping = {} + for key, value in m.items(): + remapping[value] = key + + max_abduce_num = 10 + solution = abducer.zoopt_get_solution( + pred_res, [1] * len(pred_res), max_abduce_num + ) + all_address_flag = reform_idx(solution, pred_res) + + consistent_idx_tmp = [] + consistent_pred_res_tmp = [] + + for idx in range(len(pred_res)): + address_idx = [ + i for i, flag in enumerate(all_address_flag[idx]) if flag != 0 + ] + candidate = abducer.kb.address_by_idx([pred_res[idx]], 1, address_idx, True) + if len(candidate) > 0: + consistent_idx_tmp.append(idx) + consistent_pred_res_tmp.append( + [remapping[symbol] for symbol in candidate[0][0]] + ) + + if len(consistent_idx_tmp) > len(consistent_idx): + consistent_idx = consistent_idx_tmp + consistent_pred_res = consistent_pred_res_tmp + mapping = m + + if len(consistent_idx) == 0: + return 0, 0, None + + INFO("Consistent predict results are:", map_res(consistent_pred_res, mapping)) + INFO("Train pool size is:", len(flatten(consistent_pred_res))) + INFO("Start to use abduced pseudo label to train model...") + model.train([X[idx] for idx in consistent_idx], consistent_pred_res) + + consistent_acc = len(consistent_idx) / select_num + char_acc = get_char_acc( + model, [X[idx] for idx in consistent_idx], consistent_pred_res + ) + INFO("consistent_acc is %s, char_acc is %s" % (consistent_acc, char_acc)) + return consistent_acc, char_acc, mapping + + +def get_rules_from_data( + model, abducer, mapping, train_X_true, samples_per_rule, logic_output_dim +): rules = [] for _ in range(logic_output_dim): while True: - select_index = np.random.randint(len(train_X_true), size=samples_per_rule) - select_X = train_X_true[select_index] - - ## TODO - exs = select_X.predict() - rule = get_rules(exs) - if rule != None: - break + select_idx = np.random.randint(len(train_X_true), size=samples_per_rule) + X = [] + for idx in select_idx: + X.append(train_X_true[idx]) + pred_res = model.predict(X)["cls"] + pred_res = [[mapping[symbol] for symbol in formula] for formula in pred_res] + + consistent_idx = [] + consistent_pred_res = [] + for idx in range(len(pred_res)): + if abducer.kb.logic_forward([pred_res[idx]]): + consistent_idx.append(idx) + consistent_pred_res.append(pred_res[idx]) + + if len(consistent_pred_res) != 0: + rule = abducer.abduce_rules(consistent_pred_res) + if rule != None: + break + rules.append(rule) + INFO('Learned rules from data:') + for rule in rules: + INFO(rule) return rules -def get_mlp_vector(X, rules): - - ## TODO - exs = np.argmax(model.predict(X)) - +def get_mlp_vector(model, abducer, mapping, X, rules): + pred_res = model.predict([X])["cls"] + pred_res = [[mapping[symbol] for symbol in formula] for formula in pred_res] vector = [] for rule in rules: - if abducer.kb.consist_rule(exs, rule): + if abducer.kb.consist_rule(pred_res, rule): vector.append(1) else: vector.append(0) return vector -def get_mlp_data(X_true, X_false, rules): + +def get_mlp_data(model, abducer, mapping, X_true, X_false, rules): mlp_vectors = [] mlp_labels = [] for X in X_true: - mlp_vectors.append(get_mlp_vector(X, rules)) + mlp_vectors.append(get_mlp_vector(model, abducer, mapping, X, rules)) mlp_labels.append(1) for X in X_false: - mlp_vectors.append(get_mlp_vector(X, rules)) + mlp_vectors.append(get_mlp_vector(model, abducer, mapping, X, rules)) mlp_labels.append(0) - - return np.array(mlp_vectors), np.array(mlp_labels) + + return np.array(mlp_vectors, dtype=np.float32), np.array(mlp_labels, dtype=np.int64) -def validation(train_X_true, train_X_false, val_X_true, val_X_false): - print("Now checking if we can go to next course") +def validation( + model, + abducer, + mapping, + train_X_true, + train_X_false, + val_X_true, + val_X_false, + recorder, +): + INFO("Now checking if we can go to next course") samples_per_rule = 3 logic_output_dim = 50 - print("Now checking if we can go to next course") - rules = get_rules_from_data(train_X_true, samples_per_rule, logic_output_dim) - mlp_train_vectors, mlp_train_labels = get_mlp_data(train_X_true, train_X_false, rules) - - index = np.array(list(range(len(mlp_train_labels)))) - np.random.shuffle(index) - mlp_train_vectors = mlp_train_vectors[index] - mlp_train_labels = mlp_train_labels[index] - + rules = get_rules_from_data( + model, abducer, mapping, train_X_true, samples_per_rule, logic_output_dim + ) + + mlp_train_vectors, mlp_train_labels = get_mlp_data( + model, abducer, mapping, train_X_true, train_X_false, rules + ) + + idx = np.array(list(range(len(mlp_train_labels)))) + np.random.shuffle(idx) + mlp_train_vectors = mlp_train_vectors[idx] + mlp_train_labels = mlp_train_labels[idx] + best_accuracy = 0 - - #Try three times to find the best mlp + + # Try three times to find the best mlp for _ in range(3): - print("Training mlp...") - - ### TODO - # mlp_model = get_mlp_net(logic_output_dim) - # mlp_model.compile(loss='binary_crossentropy', - # optimizer='rmsprop', - # metrics=['accuracy']) - # mlp_model.fit(mlp_train_vectors, - # mlp_train_labels, - # epochs=MLP_EPOCHS, - # batch_size=MLP_BATCHSIZE, - # verbose=0) - #Prepare MLP validation data - - mlp_val_vectors, mlp_val_labels = get_mlp_data(val_X_true, val_X_false, rules) - - ## TODO - #Get MLP validation result - # result = mlp_model.evaluate(mlp_val_vectors, - # mlp_val_labels, - # batch_size=MLP_BATCHSIZE, - # verbose=0) - print("MLP validation result:", result) - accuracy = result[1] + INFO("Training mlp...") + mlp = MLP(input_dim=logic_output_dim) + criterion = nn.CrossEntropyLoss() + optimizer = torch.optim.Adam(mlp.parameters(), lr=0.01, betas=(0.9, 0.999)) + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + mlp_model = BasicModel( + mlp, + criterion, + optimizer, + device, + batch_size=128, + num_epochs=60, + recorder=recorder, + ) + mlp_train_data = BasicDataset(mlp_train_vectors, mlp_train_labels) + mlp_train_data_loader = torch.utils.data.DataLoader( + mlp_train_data, + batch_size=128, + shuffle=True, + ) + loss = mlp_model.fit(mlp_train_data_loader) + INFO("mlp training loss is %f" % loss) + + mlp_val_vectors, mlp_val_labels = get_mlp_data( + model, abducer, mapping, val_X_true, val_X_false, rules + ) + + # Get MLP validation result + mlp_val_data = BasicDataset(mlp_val_vectors, mlp_val_labels) + mlp_val_data_loader = torch.utils.data.DataLoader( + mlp_val_data, + batch_size=64, + shuffle=True, + ) + + accuracy = mlp_model.val(mlp_val_data_loader) if accuracy > best_accuracy: best_accuracy = accuracy return best_accuracy - -def train_HED(model, abducer, train_data, test_data, epochs=50, select_num=10, verbose=-1): - train_X, train_Z, train_Y = train_data - test_X, test_Z, test_Y = test_data +def train_with_rule( + model, + abducer, + train_data, + val_data, + select_num=10, + recorder=None +): + train_X = train_data + val_X = val_data min_len = 5 max_len = 8 - cp_threshold = 0.9 - blmp_threshold = 0.9 - - cnt_threshold = 5 - acc_threshold = 0.86 - # Start training / for each length of equations for equation_len in range(min_len, max_len): - - ### TODO: get_data, e.g. - # train_X_true = train_X['True'][equation_len] - # train_X_true.append(train_X['True'][equation_len + 1]) - + INFO("============== equation_len:%d ================" % (equation_len)) + train_X_true = train_X[1][equation_len] + train_X_false = train_X[0][equation_len] + val_X_true = val_X[1][equation_len] + val_X_false = val_X[0][equation_len] + train_X_true.extend(train_X[1][equation_len + 1]) + train_X_false.extend(train_X[0][equation_len + 1]) + val_X_true.extend(val_X[1][equation_len + 1]) + val_X_false.extend(val_X[0][equation_len + 1]) + condition_cnt = 0 while True: # Abduce and train NN - consistent_percentage, batch_label_model_precision = abduce_and_train(model, abducer, train_X_true, select_num) - if consistent_percentage == 0: + consistent_acc, char_acc, mapping = abduce_and_train( + model, abducer, train_X_true, select_num + ) + if consistent_acc == 0: continue # Test if we can use mlp to evaluate - if consistent_percentage >= cp_threshold and batch_label_model_precision >= blmp_threshold: + if consistent_acc >= 0.9 and char_acc >= 0.9: condition_cnt += 1 else: condition_cnt = 0 + # The condition has been satisfied continuously five times - if condition_cnt >= cnt_threshold: - best_accuracy = validation(train_X_true, train_X_false, val_X_true, val_X_false) + if condition_cnt >= 5: + best_accuracy = validation( + model, + abducer, + mapping, + train_X_true, + train_X_false, + val_X_true, + val_X_false, + recorder, + ) + + INFO("best_accuracy is %f" % (best_accuracy)) # decide next course or restart - if best_accuracy > acc_threshold: - # Save model and go to next course - ## TODO: model.save_weights() + if best_accuracy > 0.86: + torch.save( + model.cls_list[0].model.state_dict(), + "./weights/train_weights_%d.pth" % equation_len, + ) break - else: - # Restart current course: reload model if equation_len == min_len: - ## TODO: model.set_weights(pretrain_model.get_weights()) - model.set_weights() + model.cls_list[0].model.load_state_dict( + torch.load("./weights/pretrain_weights.pth") + ) else: - ## TODO: model.load_weights() - model.load_weights() - print("Failed! Reload model.") + model.cls_list[0].model.load_state_dict( + torch.load( + "./weights/train_weights_%d.pth" % (equation_len - 1) + ) + ) condition_cnt = 0 - - return model diff --git a/models/basic_model.py b/models/basic_model.py index 11063a8..8c137e2 100644 --- a/models/basic_model.py +++ b/models/basic_model.py @@ -1,16 +1,17 @@ # coding: utf-8 -#================================================================# +# ================================================================# # Copyright (C) 2020 Freecss All rights reserved. -# +# # File Name :basic_model.py # Author :freecss # Email :karlfreecss@gmail.com # Created Date :2020/11/21 # Description : # -#================================================================# +# ================================================================# import sys + sys.path.append("..") import torch @@ -19,6 +20,24 @@ from torch.utils.data import Dataset import os from multiprocessing import Pool + +class BasicDataset(Dataset): + def __init__(self, X, Y): + self.X = X + self.Y = Y + + def __len__(self): + return len(self.X) + + def __getitem__(self, index): + assert index < len(self), "index range error" + + img = self.X[index] + label = self.Y[index] + + return (img, label) + + class XYDataset(Dataset): def __init__(self, X, Y, transform=None): self.X = X @@ -31,8 +50,8 @@ class XYDataset(Dataset): return len(self.X) def __getitem__(self, index): - assert index < len(self), 'index range error' - + assert index < len(self), "index range error" + img = self.X[index] if self.transform is not None: img = self.transform(img) @@ -41,31 +60,35 @@ class XYDataset(Dataset): return (img, label) -class FakeRecorder(): + +class FakeRecorder: def __init__(self): pass def print(self, *x): pass -class BasicModel(): - def __init__(self, - model, - criterion, - optimizer, - device, - batch_size = 1, - num_epochs = 1, - stop_loss = 0.01, - num_workers = 0, - save_interval = None, - save_dir = None, - transform = None, - collate_fn = None, - recorder = None): + +class BasicModel: + def __init__( + self, + model, + criterion, + optimizer, + device, + batch_size=1, + num_epochs=1, + stop_loss=0.01, + num_workers=0, + save_interval=None, + save_dir=None, + transform=None, + collate_fn=None, + recorder=None, + ): self.model = model.to(device) - + self.batch_size = batch_size self.num_epochs = num_epochs self.stop_loss = stop_loss @@ -103,9 +126,7 @@ class BasicModel(): recorder.print("Model fitted, minimal loss is ", min_loss) return loss_value - def fit(self, data_loader = None, - X = None, - y = None): + def fit(self, data_loader=None, X=None, y=None): if data_loader is None: data_loader = self._data_loader(X, y) return self._fit(data_loader, self.num_epochs, self.stop_loss) @@ -115,7 +136,7 @@ class BasicModel(): criterion = self.criterion optimizer = self.optimizer device = self.device - + model.train() total_loss, total_num = 0.0, 0 @@ -136,7 +157,7 @@ class BasicModel(): def _predict(self, data_loader): model = self.model device = self.device - + model.eval() with torch.no_grad(): @@ -145,20 +166,20 @@ class BasicModel(): data = data.to(device) out = model(data) results.append(out) - + return torch.cat(results, axis=0) - def predict(self, data_loader = None, X = None, print_prefix = ""): + def predict(self, data_loader=None, X=None, print_prefix=""): recorder = self.recorder - recorder.print('Start Predict Class ', print_prefix) + recorder.print("Start Predict Class ", print_prefix) if data_loader is None: data_loader = self._data_loader(X) return self._predict(data_loader).argmax(axis=1).cpu().numpy() - def predict_proba(self, data_loader = None, X = None, print_prefix = ""): + def predict_proba(self, data_loader=None, X=None, print_prefix=""): recorder = self.recorder - recorder.print('Start Predict Probability ', print_prefix) + # recorder.print('Start Predict Probability ', print_prefix) if data_loader is None: data_loader = self._data_loader(X) @@ -168,7 +189,7 @@ class BasicModel(): model = self.model criterion = self.criterion device = self.device - + model.eval() total_correct_num, total_num, total_loss = 0, 0, 0.0 @@ -179,32 +200,37 @@ class BasicModel(): out = model(data) - correct_num = sum(target == out.argmax(axis=1)).item() + if len(out.shape) > 1: + correct_num = sum(target == out.argmax(axis=1)).item() + else: + correct_num = sum(target == (out > 0.5)).item() loss = criterion(out, target) total_loss += loss.item() * data.size(0) total_correct_num += correct_num total_num += data.size(0) - + mean_loss = total_loss / total_num accuracy = total_correct_num / total_num return mean_loss, accuracy - def val(self, data_loader = None, X = None, y = None, print_prefix = ""): + def val(self, data_loader=None, X=None, y=None, print_prefix=""): recorder = self.recorder - recorder.print('Start val ', print_prefix) + recorder.print("Start val ", print_prefix) if data_loader is None: data_loader = self._data_loader(X, y) mean_loss, accuracy = self._val(data_loader) - recorder.print('[%s] Val loss: %f, accuray: %f' % (print_prefix, mean_loss, accuracy)) + recorder.print( + "[%s] Val loss: %f, accuray: %f" % (print_prefix, mean_loss, accuracy) + ) return accuracy - def score(self, data_loader = None, X = None, y = None, print_prefix = ""): + def score(self, data_loader=None, X=None, y=None, print_prefix=""): return self.val(data_loader, X, y, print_prefix) - def _data_loader(self, X, y = None): + def _data_loader(self, X, y=None): collate_fn = self.collate_fn transform = self.transform @@ -212,9 +238,14 @@ class BasicModel(): y = [0] * len(X) dataset = XYDataset(X, y, transform=transform) sampler = None - data_loader = torch.utils.data.DataLoader(dataset, batch_size=self.batch_size, \ - shuffle=False, sampler=sampler, num_workers=int(self.num_workers), \ - collate_fn=collate_fn) + data_loader = torch.utils.data.DataLoader( + dataset, + batch_size=self.batch_size, + shuffle=False, + sampler=sampler, + num_workers=int(self.num_workers), + collate_fn=collate_fn, + ) return data_loader def save(self, epoch_id, save_dir): @@ -237,7 +268,6 @@ class BasicModel(): load_path = os.path.join(load_dir, str(epoch_id) + "_opt.pth") self.optimizer.load_state_dict(torch.load(load_path)) + if __name__ == "__main__": pass - - diff --git a/models/nn.py b/models/nn.py new file mode 100644 index 0000000..cecbeea --- /dev/null +++ b/models/nn.py @@ -0,0 +1,152 @@ +# coding: utf-8 +# ================================================================# +# Copyright (C) 2021 Freecss All rights reserved. +# +# File Name :lenet5.py +# Author :freecss +# Email :karlfreecss@gmail.com +# Created Date :2021/03/03 +# Description : +# +# ================================================================# + +import sys + +sys.path.append("..") + +import torchvision + +import torch +from torch import nn +from torch.nn import functional as F +from torch.autograd import Variable +import torchvision.transforms as transforms +import numpy as np + +from models.basic_model import BasicModel +import utils.plog as plog + + +class LeNet5(nn.Module): + def __init__(self, num_classes=10, image_size=(28, 28)): + super().__init__() + self.conv1 = nn.Conv2d(1, 6, 3, padding=1) + self.conv2 = nn.Conv2d(6, 16, 3) + self.conv3 = nn.Conv2d(16, 16, 3) + + feature_map_size = (np.array(image_size) // 2 - 2) // 2 - 2 + num_features = 16 * feature_map_size[0] * feature_map_size[1] + + self.fc1 = nn.Linear(num_features, 120) + self.fc2 = nn.Linear(120, 84) + self.fc3 = nn.Linear(84, num_classes) + + def forward(self, x): + """å‰å‘传播函数""" + x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) + x = F.max_pool2d(F.relu(self.conv2(x)), (2, 2)) + x = F.relu(self.conv3(x)) + x = x.view(-1, self.num_flat_features(x)) + # print(x.size()) + x = F.relu(self.fc1(x)) + x = F.relu(self.fc2(x)) + x = self.fc3(x) + return x + + def num_flat_features(self, x): + size = x.size()[1:] + num_features = 1 + for s in size: + num_features *= s + return num_features + + +# class SymbolNet(nn.Module): +# def __init__(self, num_classes=4, image_size=(28, 28, 1)): +# super(SymbolNet, self).__init__() +# self.conv1 = nn.Sequential( +# nn.Conv2d(1, 32, 3, stride=1, padding=1), +# nn.ReLU(inplace=True), +# nn.BatchNorm2d(32), +# ) +# self.conv2 = nn.Sequential( +# nn.Conv2d(32, 64, 3, stride=1, padding=1), +# nn.ReLU(inplace=True), +# nn.MaxPool2d(kernel_size=2, stride=2), +# nn.BatchNorm2d(64), +# nn.Dropout(0.25), +# ) +# num_features = 64 * (image_size[0] // 2) * (image_size[1] // 2) +# self.fc1 = nn.Sequential( +# nn.Linear(num_features, 128), nn.ReLU(inplace=True), nn.Dropout(0.5) +# ) +# self.fc2 = nn.Sequential(nn.Linear(128, num_classes), nn.Softmax(dim=1)) + +# def forward(self, x): +# x = self.conv1(x) +# x = self.conv2(x) +# x = torch.flatten(x, 1) +# x = self.fc1(x) +# x = self.fc2(x) +# return x + + +class SymbolNet(nn.Module): + def __init__(self, num_classes=4, image_size=(28, 28, 1)): + super(SymbolNet, self).__init__() + self.conv1 = nn.Sequential( + nn.Conv2d(1, 32, 5, stride=1), + nn.ReLU(), + nn.MaxPool2d(kernel_size=2, stride=2), + nn.BatchNorm2d(32, momentum=0.99, eps=0.001), + ) + self.conv2 = nn.Sequential( + nn.Conv2d(32, 64, 5, padding=2, stride=1), + nn.ReLU(), + nn.MaxPool2d(kernel_size=2, stride=2), + nn.BatchNorm2d(64, momentum=0.99, eps=0.001), + ) + + num_features = 64 * (image_size[0] // 4 - 1) * (image_size[1] // 4 - 1) + self.fc1 = nn.Sequential(nn.Linear(num_features, 120), nn.ReLU()) + self.fc2 = nn.Sequential(nn.Linear(120, 84), nn.ReLU()) + self.fc3 = nn.Sequential(nn.Linear(84, num_classes), nn.Softmax(dim=1)) + + def forward(self, x): + x = self.conv1(x) + x = self.conv2(x) + x = torch.flatten(x, 1) + x = self.fc1(x) + x = self.fc2(x) + x = self.fc3(x) + return x + + +class SymbolNetAutoencoder(nn.Module): + def __init__(self, num_classes=4, image_size=(28, 28, 1)): + super(SymbolNetAutoencoder, self).__init__() + self.base_model = SymbolNet(num_classes, image_size) + self.fc1 = nn.Sequential(nn.Linear(num_classes, 100), nn.ReLU()) + self.fc2 = nn.Sequential( + nn.Linear(100, image_size[0] * image_size[1]), nn.ReLU() + ) + + def forward(self, x): + x = self.base_model(x) + x = self.fc1(x) + x = self.fc2(x) + return x + + +class MLP(nn.Module): + def __init__(self, input_dim=50, num_classes=2): + super(MLP, self).__init__() + assert input_dim > 0 + hidden_dim = int(np.sqrt(input_dim)) + self.fc1 = nn.Sequential(nn.Linear(input_dim, hidden_dim), nn.ReLU()) + self.fc2 = nn.Sequential(nn.Linear(hidden_dim, num_classes), nn.Softmax(dim=1)) + + def forward(self, x): + x = self.fc1(x) + x = self.fc2(x) + return x diff --git a/models/wabl_models.py b/models/wabl_models.py index b854039..9c97bbc 100644 --- a/models/wabl_models.py +++ b/models/wabl_models.py @@ -1,14 +1,14 @@ # coding: utf-8 -#================================================================# +# ================================================================# # Copyright (C) 2020 Freecss All rights reserved. -# +# # File Name :models.py # Author :freecss # Email :karlfreecss@gmail.com # Created Date :2020/04/02 # Description : # -#================================================================# +# ================================================================# from itertools import chain from sklearn.tree import DecisionTreeClassifier @@ -29,14 +29,17 @@ import random from sklearn.neighbors import KNeighborsClassifier import numpy as np + def get_part_data(X, i): - return list(map(lambda x : x[i], X)) + return list(map(lambda x: x[i], X)) + def merge_data(X): - ret_mark = list(map(lambda x : len(x), X)) + ret_mark = list(map(lambda x: len(x), X)) ret_X = list(chain(*X)) return ret_X, ret_mark + def reshape_data(Y, marks): begin_mark = 0 ret_Y = [] @@ -48,42 +51,44 @@ def reshape_data(Y, marks): class WABLBasicModel: - def __init__(self, base_model, pseudo_label_list): self.cls_list = [] self.cls_list.append(base_model) self.pseudo_label_list = pseudo_label_list self.mapping = dict(zip(pseudo_label_list, list(range(len(pseudo_label_list))))) - self.remapping = dict(zip(list(range(len(pseudo_label_list))), pseudo_label_list)) + self.remapping = dict( + zip(list(range(len(pseudo_label_list))), pseudo_label_list) + ) def predict(self, X): data_X, marks = merge_data(X) - prob = self.cls_list[0].predict_proba(X = data_X) - _cls = prob.argmax(axis = 1) - cls = list(map(lambda x : self.remapping[x], _cls)) + prob = self.cls_list[0].predict_proba(X=data_X) + _cls = prob.argmax(axis=1) + cls = list(map(lambda x: self.remapping[x], _cls)) prob = reshape_data(prob, marks) cls = reshape_data(cls, marks) - return {"cls" : cls, "prob" : prob} + return {"cls": cls, "prob": prob} def valid(self, X, Y): data_X, _ = merge_data(X) _data_Y, _ = merge_data(Y) - data_Y = list(map(lambda y : self.mapping[y], _data_Y)) - score = self.cls_list[0].score(X = data_X, y = data_Y) + data_Y = list(map(lambda y: self.mapping[y], _data_Y)) + score = self.cls_list[0].score(X=data_X, y=data_Y) return score, [score] def train(self, X, Y): - #self.label_lists = [] + # self.label_lists = [] data_X, _ = merge_data(X) _data_Y, _ = merge_data(Y) - data_Y = list(map(lambda y : self.mapping[y], _data_Y)) - self.cls_list[0].fit(X = data_X, y = data_Y) + data_Y = list(map(lambda y: self.mapping[y], _data_Y)) + self.cls_list[0].fit(X=data_X, y=data_Y) + class DecisionTree(WABLBasicModel): - def __init__(self, code_len, label_lists, share = False): + def __init__(self, code_len, label_lists, share=False): self.code_len = code_len self._set_label_lists(label_lists) @@ -91,14 +96,19 @@ class DecisionTree(WABLBasicModel): self.share = share if share: # 本质上是åŒä¸€ä¸ªåˆ†ç±»å™¨ - self.cls_list.append(DecisionTreeClassifier(random_state = 0, min_samples_leaf = 3)) + self.cls_list.append( + DecisionTreeClassifier(random_state=0, min_samples_leaf=3) + ) self.cls_list = self.cls_list * self.code_len else: for _ in range(code_len): - self.cls_list.append(DecisionTreeClassifier(random_state = 0, min_samples_leaf = 3)) + self.cls_list.append( + DecisionTreeClassifier(random_state=0, min_samples_leaf=3) + ) + class KNN(WABLBasicModel): - def __init__(self, code_len, label_lists, share = False, k = 3): + def __init__(self, code_len, label_lists, share=False, k=3): self.code_len = code_len self._set_label_lists(label_lists) @@ -106,14 +116,15 @@ class KNN(WABLBasicModel): self.share = share if share: # 本质上是åŒä¸€ä¸ªåˆ†ç±»å™¨ - self.cls_list.append(KNeighborsClassifier(n_neighbors = k)) + self.cls_list.append(KNeighborsClassifier(n_neighbors=k)) self.cls_list = self.cls_list * self.code_len else: for _ in range(code_len): - self.cls_list.append(KNeighborsClassifier(n_neighbors = k)) + self.cls_list.append(KNeighborsClassifier(n_neighbors=k)) + class CNN(WABLBasicModel): - def __init__(self, base_model, code_len, label_lists, share = True): + def __init__(self, base_model, code_len, label_lists, share=True): assert share == True, "Not implemented" label_lists = [sorted(list(set(label_list))) for label_list in label_lists] @@ -126,27 +137,28 @@ class CNN(WABLBasicModel): if share: self.cls_list.append(base_model) - def train(self, X, Y, n_epoch = 100): - #self.label_lists = [] + def train(self, X, Y, n_epoch=100): + # self.label_lists = [] if self.share: # 因为是åŒä¸€ä¸ªåˆ†ç±»å™¨ï¼Œæ‰€ä»¥åªéœ€è¦æŠŠæ•°æ®æ”¾åœ¨ä¸€èµ·ï¼Œç„¶åŽè®­ç»ƒå…¶ä¸­ä»»æ„一个å³å¯ data_X, _ = merge_data(X) data_Y, _ = merge_data(Y) - self.cls_list[0].fit(X = data_X, y = data_Y, n_epoch = n_epoch) - #self.label_lists = [sorted(list(set(data_Y)))] * self.code_len + self.cls_list[0].fit(X=data_X, y=data_Y, n_epoch=n_epoch) + # self.label_lists = [sorted(list(set(data_Y)))] * self.code_len else: for i in range(self.code_len): data_X = get_part_data(X, i) data_Y = get_part_data(Y, i) self.cls_list[i].fit(data_X, data_Y) - #self.label_lists.append(sorted(list(set(data_Y)))) + # self.label_lists.append(sorted(list(set(data_Y)))) + if __name__ == "__main__": - #data_path = "utils/hamming_data/generated_data/hamming_7_3_0.20.pk" + # data_path = "utils/hamming_data/generated_data/hamming_7_3_0.20.pk" data_path = "datasets/generated_data/0_code_7_2_0.00.pk" codes, data, labels = pk.load(open(data_path, "rb")) - - cls = KNN(7, False, k = 3) + + cls = KNN(7, False, k=3) cls.train(data, labels) print(cls.valid(data, labels)) for res in cls.predict_proba(data): @@ -157,4 +169,3 @@ if __name__ == "__main__": print(res) break print("Trained") - diff --git a/utils/plog.py b/utils/plog.py index 0b8f5b5..3f091cb 100644 --- a/utils/plog.py +++ b/utils/plog.py @@ -1,14 +1,14 @@ # coding: utf-8 -#================================================================# +# ================================================================# # Copyright (C) 2020 Freecss All rights reserved. -# +# # File Name :plog.py # Author :freecss # Email :karlfreecss@gmail.com # Created Date :2020/10/23 # Description : # -#================================================================# +# ================================================================# import time import logging @@ -19,13 +19,14 @@ import functools global recorder recorder = None + class ResultRecorder: def __init__(self): - logging.basicConfig(level=logging.DEBUG, filemode='a') + logging.basicConfig(level=logging.DEBUG, filemode="a") self.result = {} self.set_savefile() - + logging.info("===========================================================") logging.info("============= Result Recorder Version: 0.03 ===============") logging.info("===========================================================\n") @@ -33,25 +34,25 @@ class ResultRecorder: pass def set_savefile(self): - local_time = time.strftime("%Y%m%d_%H_%M_%S", time.localtime()) + local_time = time.strftime("%Y%m%d_%H_%M_%S", time.localtime()) save_dir = os.path.join("results", local_time) if not os.path.exists(save_dir): os.makedirs(save_dir) save_file_path = os.path.join(save_dir, "result.pk") save_file = open(save_file_path, "wb") - + self.save_dir = save_dir self.save_file = save_file filename = os.path.join(save_dir, "log.txt") file_handler = logging.FileHandler(filename) file_handler.setLevel(logging.DEBUG) - formatter = logging.Formatter('%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') + formatter = logging.Formatter("%(asctime)s - %(levelname)s: %(message)s") file_handler.setFormatter(formatter) logging.getLogger().addHandler(file_handler) - def print(self, *argv, screen = False): + def print(self, *argv, screen=False): info = "" for data in argv: info += str(data) @@ -62,9 +63,8 @@ class ResultRecorder: def print_result(self, *argv): for data in argv: info = "#Result# %s" % str(data) - #print(info) logging.info(info) - + def store(self, *argv): for data in argv: if data.find(":") < 0: @@ -81,11 +81,11 @@ class ResultRecorder: self.result[label].append(data) def write_kv(self, label, data): - self.print_result({label : data}) - #self.print_result(label + ":" + str(data)) + self.print_result({label: data}) + # self.print_result(label + ":" + str(data)) self.store_kv(label, data) - def dump(self, save_file = None): + def dump(self, save_file=None): if save_file is None: save_file = self.save_file pk.dump(self.result, save_file) @@ -104,38 +104,43 @@ class ResultRecorder: self.write_kv("func:", context) return result + return clocked def __del__(self): self.dump() + def clocker(*argv): global recorder if recorder is None: recorder = ResultRecorder() return recorder.clock(*argv) -def INFO(*argv, screen = False): + +def INFO(*argv, screen=False): global recorder if recorder is None: recorder = ResultRecorder() - return recorder.print(*argv, screen = screen) + return recorder.print(*argv, screen=screen) + -def DEBUG(*argv, screen = False): +def DEBUG(*argv, screen=False): global recorder if recorder is None: recorder = ResultRecorder() - return recorder.print(*argv, screen = screen) + return recorder.print(*argv, screen=screen) + def logger(): global recorder if recorder is None: recorder = ResultRecorder() return recorder - + + if __name__ == "__main__": recorder = ResultRecorder() recorder.write_kv("test", 1) - recorder.set_savefile(pk_dir = "haha") + recorder.set_savefile(pk_dir="haha") recorder.write_kv("test", 1) - diff --git a/utils/utils.py b/utils/utils.py index 44ba6a1..57dea31 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -1,9 +1,17 @@ import numpy as np +from utils.plog import INFO +from collections import OrderedDict + # for multiple predictions, modify from `learn_add.py` def flatten(l): - return [item for sublist in l for item in flatten(sublist)] if isinstance(l, list) else [l] - + return ( + [item for sublist in l for item in flatten(sublist)] + if isinstance(l, list) + else [l] + ) + + # for multiple predictions, modify from `learn_add.py` def reform_idx(flatten_pred_res, save_pred_res): re = [] @@ -18,10 +26,25 @@ def reform_idx(flatten_pred_res, save_pred_res): i = i + j return re + +def block_sample(X, Z, Y, sample_num, epoch_idx): + part_num = len(X) // sample_num + if part_num == 0: + part_num = 1 + seg_idx = epoch_idx % part_num + INFO("seg_idx:", seg_idx, ", part num:", part_num, ", data num:", len(X)) + X = X[sample_num * seg_idx : sample_num * (seg_idx + 1)] + Z = Z[sample_num * seg_idx : sample_num * (seg_idx + 1)] + Y = Y[sample_num * seg_idx : sample_num * (seg_idx + 1)] + + return X, Z, Y + + def hamming_dist(A, B): B = np.array(B) - A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) - return np.sum(A != B, axis = 1) + A = np.expand_dims(A, axis=0).repeat(axis=0, repeats=(len(B))) + return np.sum(A != B, axis=1) + def confidence_dist(A, B): B = np.array(B) @@ -29,7 +52,16 @@ def confidence_dist(A, B): A = np.expand_dims(A, axis=0) A = A.repeat(axis=0, repeats=(len(B))) rows = np.array(range(len(B))) - rows = np.expand_dims(rows, axis = 1).repeat(axis = 1, repeats = len(B[0])) + rows = np.expand_dims(rows, axis=1).repeat(axis=1, repeats=len(B[0])) cols = np.array(range(len(B[0]))) - cols = np.expand_dims(cols, axis = 0).repeat(axis = 0, repeats = len(B)) - return 1 - np.prod(A[rows, cols, B], axis = 1) + cols = np.expand_dims(cols, axis=0).repeat(axis=0, repeats=len(B)) + return 1 - np.prod(A[rows, cols, B], axis=1) + + +def copy_state_dict(state_dict): + new_state_dict = OrderedDict() + for k, v in state_dict.items(): + if k.startswith('base_model'): + name = ".".join(k.split(".")[1:]) + new_state_dict[name] = v + return new_state_dict From 26a8ceeac6f94a7bcc62a54b0f821366a46da772 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 20 Feb 2023 14:36:40 +0800 Subject: [PATCH 127/601] Update example.py --- example.py | 79 +++++++++++++++++++++++------------------------------- 1 file changed, 34 insertions(+), 45 deletions(-) diff --git a/example.py b/example.py index 795d455..29c7629 100644 --- a/example.py +++ b/example.py @@ -11,14 +11,13 @@ # ================================================================# from utils.plog import logger, INFO -import framework_hed +from utils.utils import copy_state_dict import torch.nn as nn import torch - from models.nn import LeNet5, SymbolNet, SymbolNetAutoencoder from models.basic_model import BasicModel, BasicDataset -from models.wabl_models import WABLBasicModel +from models.wabl_models import DecisionTree, WABLBasicModel from multiprocessing import Pool import os @@ -26,14 +25,15 @@ from abducer.abducer_base import AbducerBase from abducer.kb import add_KB, HWF_KB, HED_prolog_KB from datasets.mnist_add.get_mnist_add import get_mnist_add from datasets.hwf.get_hwf import get_hwf -from datasets.hed.get_hed import get_hed, get_pretrain_data, split_equation +from datasets.hed.get_hed import get_hed, split_equation, get_pretrain_data +import framework def run_test(): # kb = add_KB(True) - # kb = hwf_KB(True) + # kb = HWF_KB(True) # abducer = AbducerBase(kb) kb = HED_prolog_KB() @@ -41,58 +41,47 @@ def run_test(): recorder = logger() - # train_X, train_Z, train_Y = get_mnist_add(train=True, get_pseudo_label=True) - # test_X, test_Z, test_Y = get_mnist_add(train=False, get_pseudo_label=True) - - # train_data = get_hwf(train=True, get_pseudo_label=True) - # test_data = get_hwf(train=False, get_pseudo_label=True) - total_train_data = get_hed(train=True) train_data, val_data = split_equation(total_train_data, 3, 1) test_data = get_hed(train=False) - + # cls = LeNet5(num_classes=len(kb.pseudo_label_list), image_size=(train_data[0][0][0].shape[1:])) cls_autoencoder = SymbolNetAutoencoder(num_classes=len(kb.pseudo_label_list)) cls = SymbolNet(num_classes=len(kb.pseudo_label_list)) - + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + if not os.path.exists("./weights/pretrain_weights.pth"): - pretrain_data_X, pretrain_data_Y = get_pretrain_data(["0", "1", "10", "11"]) + INFO("Pretrain Start") + pretrain_data_X, pretrain_data_Y = get_pretrain_data(['0', '1', '10', '11']) pretrain_data = BasicDataset(pretrain_data_X, pretrain_data_Y) - pretrain_data_loader = torch.utils.data.DataLoader( - pretrain_data, - batch_size=64, - shuffle=True, - ) - framework_hed.pretrain(cls_autoencoder, pretrain_data_loader, recorder) - torch.save( - cls_autoencoder.base_model.state_dict(), "./weights/pretrain_weights.pth" - ) - cls.load_state_dict(torch.load("./weights/pretrain_weights.pth")) - + + criterion = nn.MSELoss() + optimizer = torch.optim.RMSprop(cls_autoencoder.parameters(), lr=0.001, alpha=0.9, weight_decay=1e-6) + + pretrain_model = BasicModel(cls_autoencoder, criterion, optimizer, device, save_interval=1, save_dir=recorder.save_dir, num_epochs=10, recorder=recorder) + framework.pretrain(pretrain_model, pretrain_data) + torch.save(cls_autoencoder.base_model.state_dict(), "./weights/pretrain_weights.pth") + cls.load_state_dict(cls_autoencoder.base_model.state_dict()) + + else: + cls.load_state_dict(torch.load("./weights/pretrain_weights.pth")) + criterion = nn.CrossEntropyLoss() - optimizer = torch.optim.RMSprop( - cls.parameters(), lr=0.001, alpha=0.9, weight_decay=1e-6 - ) - device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - - base_model = BasicModel( - cls, - criterion, - optimizer, - device, - save_interval=1, - save_dir=recorder.save_dir, - batch_size=32, - num_epochs=10, - recorder=recorder, - ) + optimizer = torch.optim.RMSprop(cls.parameters(), lr=0.001, weight_decay=1e-6) + # optimizer = torch.optim.Adam(cls.parameters(), lr=0.00001, betas=(0.9, 0.99)) + + base_model = BasicModel(cls, criterion, optimizer, device, save_interval=1, save_dir=recorder.save_dir, batch_size=32, num_epochs=10, recorder=recorder) model = WABLBasicModel(base_model, kb.pseudo_label_list) + + # train_X, train_Z, train_Y = get_mnist_add(train = True, get_pseudo_label = True) + # test_X, test_Z, test_Y = get_mnist_add(train = False, get_pseudo_label = True) + + # train_data = get_hwf(train = True, get_pseudo_label = True) + # test_data = get_hwf(train = False, get_pseudo_label = True) - res = framework_hed.train_with_rule( - model, abducer, train_data, val_data, recorder=recorder - ) - INFO(res) + framework.train_with_rule(model, abducer, train_data, val_data, select_num=10, verbose=1) + # recorder.print(res) recorder.dump() return True From 85ba22bc27eca089cc308542612264ca5a4a47df Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 20 Feb 2023 14:37:20 +0800 Subject: [PATCH 128/601] Update example.py --- example.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/example.py b/example.py index 29c7629..a81b51d 100644 --- a/example.py +++ b/example.py @@ -26,7 +26,7 @@ from abducer.kb import add_KB, HWF_KB, HED_prolog_KB from datasets.mnist_add.get_mnist_add import get_mnist_add from datasets.hwf.get_hwf import get_hwf from datasets.hed.get_hed import get_hed, split_equation, get_pretrain_data -import framework +import framework_hed def run_test(): @@ -59,7 +59,7 @@ def run_test(): optimizer = torch.optim.RMSprop(cls_autoencoder.parameters(), lr=0.001, alpha=0.9, weight_decay=1e-6) pretrain_model = BasicModel(cls_autoencoder, criterion, optimizer, device, save_interval=1, save_dir=recorder.save_dir, num_epochs=10, recorder=recorder) - framework.pretrain(pretrain_model, pretrain_data) + framework_hed.pretrain(pretrain_model, pretrain_data) torch.save(cls_autoencoder.base_model.state_dict(), "./weights/pretrain_weights.pth") cls.load_state_dict(cls_autoencoder.base_model.state_dict()) @@ -80,7 +80,7 @@ def run_test(): # train_data = get_hwf(train = True, get_pseudo_label = True) # test_data = get_hwf(train = False, get_pseudo_label = True) - framework.train_with_rule(model, abducer, train_data, val_data, select_num=10, verbose=1) + framework_hed.train_with_rule(model, abducer, train_data, val_data, select_num=10, verbose=1) # recorder.print(res) recorder.dump() From 3678d2d0adac4aea352cc937456d3855c0bfba4b Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 20 Feb 2023 14:38:12 +0800 Subject: [PATCH 129/601] Update framework_hed.py --- framework_hed.py | 295 ++++++++++++++++++++--------------------------- 1 file changed, 128 insertions(+), 167 deletions(-) diff --git a/framework_hed.py b/framework_hed.py index 04b41b8..36159da 100644 --- a/framework_hed.py +++ b/framework_hed.py @@ -11,26 +11,18 @@ # ================================================================# import pickle as pk - -import numpy as np - -import random - -random_seed = random.randint(0, 10000) -print("Selected random seed is : ", random_seed) -np.random.seed(random_seed) -random.seed(random_seed) - -from models.nn import MLP -from models.basic_model import BasicModel, BasicDataset -import torch.nn as nn +import math import torch +import torch.nn as nn +import numpy as np from utils.plog import INFO, DEBUG, clocker from utils.utils import flatten, reform_idx, block_sample +from utils.utils import copy_state_dict -from sklearn.tree import DecisionTreeClassifier - +from sklearn.linear_model import LogisticRegression +from models.nn import MLP +from models.basic_model import BasicModel, BasicDataset def result_statistics(pred_Z, Z, Y, logic_forward, char_acc_flag): result = {} @@ -65,59 +57,89 @@ def filter_data(X, abduced_Z): return finetune_X, finetune_Z -def pretrain(net, pretrain_data_loader, recorder): - INFO("Pretrain Start") + + +def train(model, abducer, train_data, test_data, epochs=50, sample_num=-1, verbose=-1): + train_X, train_Z, train_Y = train_data + test_X, test_Z, test_Y = test_data - criterion = nn.MSELoss() - optimizer = torch.optim.RMSprop( - net.parameters(), lr=0.001, alpha=0.9, weight_decay=1e-6 - ) - device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - - pretrain_model = BasicModel( - net, - criterion, - optimizer, - device, - save_interval=1, - save_dir=recorder.save_dir, - num_epochs=10, - recorder=recorder, - ) + # Set default parameters + if sample_num == -1: + sample_num = len(train_X) - pretrain_model.fit(pretrain_data_loader) + if verbose < 1: + verbose = epochs + char_acc_flag = 1 + if train_Z == None: + char_acc_flag = 0 + train_Z = [None] * len(train_X) -def get_char_acc(model, X, consistent_pred_res): - pred_res = flatten(model.predict(X)["cls"]) - assert len(pred_res) == len(flatten(consistent_pred_res)) - return sum( - [ - pred_res[idx] == flatten(consistent_pred_res)[idx] - for idx in range(len(pred_res)) - ] - ) / len(pred_res) + predict_func = clocker(model.predict) + train_func = clocker(model.train) + abduce_func = clocker(abducer.batch_abduce) + for epoch_idx in range(epochs): + X, Z, Y = block_sample(train_X, train_Z, train_Y, sample_num, epoch_idx) + preds_res = predict_func(X) + # input() + abduced_Z = abduce_func(preds_res, Y) -def gen_mappings(chars, symbs): - n_char = len(chars) - n_symbs = len(symbs) - if n_char != n_symbs: - INFO("Characters and symbols size dosen't match.") - return - from itertools import permutations + if ((epoch_idx + 1) % verbose == 0) or (epoch_idx == epochs - 1): + res = result_statistics(preds_res['cls'], Z, Y, abducer.kb.logic_forward, char_acc_flag) + INFO('epoch: ', epoch_idx + 1, ' ', res) + + finetune_X, finetune_Z = filter_data(X, abduced_Z) + if len(finetune_X) > 0: + # model.valid(finetune_X, finetune_Z) + train_func(finetune_X, finetune_Z) + else: + INFO("lack of data, all abduced failed", len(finetune_X)) - mappings = [] - perms = permutations(symbs) - for p in perms: - mappings.append(dict(zip(chars, list(p)))) - return mappings + return res -def map_res(original_pred_res, m): - pred_res = [[m[symbol] for symbol in formula] for formula in original_pred_res] + +def pretrain(pretrain_model, pretrain_data): + INFO("Pretrain Start") + pretrain_data_loader = torch.utils.data.DataLoader( + pretrain_data, + batch_size=64, + shuffle=True, + num_workers=2, + ) + pretrain_model.fit(pretrain_data_loader) + + +def get_char_acc(model, X, consistent_pred_res): + print('Abduced labels: ', flatten(consistent_pred_res)) + pred_res = flatten(model.predict(X)['cls']) + print('Current model\'s output:', pred_res) + assert len(pred_res) == len(flatten(consistent_pred_res)) + return sum([pred_res[idx] == flatten(consistent_pred_res)[idx] for idx in range(len(pred_res))]) / len(pred_res) + +def gen_mappings(chars, symbs): + n_char = len(chars) + n_symbs = len(symbs) + if n_char != n_symbs: + print('Characters and symbols size dosen\'t match.') + return + from itertools import permutations + mappings = [] + # returned mappings + perms = permutations(symbs) + for p in perms: + mappings.append(dict(zip(chars, list(p)))) + return mappings + +def map_res(pred_res, m): + for i in range(len(pred_res)): + for j in range(len(pred_res[i])): + pred_res[i][j] = m[pred_res[i][j]] return pred_res +def map_res(original_pred_res, m): + return [[m[symbol] for symbol in formula] for formula in original_pred_res] def abduce_and_train(model, abducer, train_X_true, select_num): select_idx = np.random.randint(len(train_X_true), size=select_num) @@ -125,68 +147,59 @@ def abduce_and_train(model, abducer, train_X_true, select_num): for idx in select_idx: X.append(train_X_true[idx]) - pred_res = model.predict(X)["cls"] - - maps = gen_mappings(["+", "=", 0, 1], ["+", "=", 0, 1]) - + pred_res = model.predict(X)['cls'] + + maps = gen_mappings(['+', '=', 0, 1],['+', '=', 0, 1]) + consistent_idx = [] consistent_pred_res = [] - + import copy original_pred_res = copy.deepcopy(pred_res) mapping = None - + for m in maps: pred_res = map_res(original_pred_res, m) remapping = {} for key, value in m.items(): remapping[value] = key - - max_abduce_num = 10 - solution = abducer.zoopt_get_solution( - pred_res, [1] * len(pred_res), max_abduce_num - ) + + max_abduce_num = 20 + solution = abducer.zoopt_get_solution(pred_res, [1] * len(pred_res), max_abduce_num) all_address_flag = reform_idx(solution, pred_res) consistent_idx_tmp = [] consistent_pred_res_tmp = [] - + for idx in range(len(pred_res)): - address_idx = [ - i for i, flag in enumerate(all_address_flag[idx]) if flag != 0 - ] + address_idx = [i for i, flag in enumerate(all_address_flag[idx]) if flag != 0] candidate = abducer.kb.address_by_idx([pred_res[idx]], 1, address_idx, True) if len(candidate) > 0: consistent_idx_tmp.append(idx) - consistent_pred_res_tmp.append( - [remapping[symbol] for symbol in candidate[0][0]] - ) - + consistent_pred_res_tmp.append([remapping[symbol] for symbol in candidate[0][0]]) + if len(consistent_idx_tmp) > len(consistent_idx): consistent_idx = consistent_idx_tmp consistent_pred_res = consistent_pred_res_tmp mapping = m - + if len(consistent_idx) == 0: return 0, 0, None - - INFO("Consistent predict results are:", map_res(consistent_pred_res, mapping)) - INFO("Train pool size is:", len(flatten(consistent_pred_res))) + + INFO("Consistent predict results are: ", map_res(consistent_pred_res, mapping)) + INFO('Train pool size is:', len(flatten(consistent_pred_res))) + INFO("Start to use abduced pseudo label to train model...") model.train([X[idx] for idx in consistent_idx], consistent_pred_res) consistent_acc = len(consistent_idx) / select_num - char_acc = get_char_acc( - model, [X[idx] for idx in consistent_idx], consistent_pred_res - ) - INFO("consistent_acc is %s, char_acc is %s" % (consistent_acc, char_acc)) + char_acc = get_char_acc(model, [X[idx] for idx in consistent_idx], consistent_pred_res) + INFO('consistent_acc is %s, char_acc is %s' % (consistent_acc, char_acc)) return consistent_acc, char_acc, mapping -def get_rules_from_data( - model, abducer, mapping, train_X_true, samples_per_rule, logic_output_dim -): +def get_rules_from_data(model, abducer, mapping, train_X_true, samples_per_rule, logic_output_dim): rules = [] for _ in range(logic_output_dim): while True: @@ -194,8 +207,8 @@ def get_rules_from_data( X = [] for idx in select_idx: X.append(train_X_true[idx]) - pred_res = model.predict(X)["cls"] - pred_res = [[mapping[symbol] for symbol in formula] for formula in pred_res] + original_pred_res = model.predict(X)['cls'] + pred_res = map_res(original_pred_res, mapping) consistent_idx = [] consistent_pred_res = [] @@ -208,17 +221,16 @@ def get_rules_from_data( rule = abducer.abduce_rules(consistent_pred_res) if rule != None: break - rules.append(rule) + INFO('Learned rules from data:') - for rule in rules: - INFO(rule) + INFO(rules) return rules def get_mlp_vector(model, abducer, mapping, X, rules): - pred_res = model.predict([X])["cls"] - pred_res = [[mapping[symbol] for symbol in formula] for formula in pred_res] + original_pred_res = model.predict([X])['cls'] + pred_res = map_res(original_pred_res, mapping) vector = [] for rule in rules: if abducer.kb.consist_rule(pred_res, rule): @@ -241,26 +253,13 @@ def get_mlp_data(model, abducer, mapping, X_true, X_false, rules): return np.array(mlp_vectors, dtype=np.float32), np.array(mlp_labels, dtype=np.int64) -def validation( - model, - abducer, - mapping, - train_X_true, - train_X_false, - val_X_true, - val_X_false, - recorder, -): +def validation(model, abducer, mapping, train_X_true, train_X_false, val_X_true, val_X_false): INFO("Now checking if we can go to next course") samples_per_rule = 3 logic_output_dim = 50 - rules = get_rules_from_data( - model, abducer, mapping, train_X_true, samples_per_rule, logic_output_dim - ) + rules = get_rules_from_data(model, abducer, mapping, train_X_true, samples_per_rule, logic_output_dim) - mlp_train_vectors, mlp_train_labels = get_mlp_data( - model, abducer, mapping, train_X_true, train_X_false, rules - ) + mlp_train_vectors, mlp_train_labels = get_mlp_data(model, abducer, mapping, train_X_true, train_X_false, rules) idx = np.array(list(range(len(mlp_train_labels)))) np.random.shuffle(idx) @@ -276,28 +275,18 @@ def validation( criterion = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(mlp.parameters(), lr=0.01, betas=(0.9, 0.999)) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - - mlp_model = BasicModel( - mlp, - criterion, - optimizer, - device, - batch_size=128, - num_epochs=60, - recorder=recorder, - ) + + mlp_model = BasicModel(mlp, criterion, optimizer, device, batch_size=128, num_epochs=60) mlp_train_data = BasicDataset(mlp_train_vectors, mlp_train_labels) mlp_train_data_loader = torch.utils.data.DataLoader( mlp_train_data, batch_size=128, - shuffle=True, + shuffle=True ) loss = mlp_model.fit(mlp_train_data_loader) INFO("mlp training loss is %f" % loss) - - mlp_val_vectors, mlp_val_labels = get_mlp_data( - model, abducer, mapping, val_X_true, val_X_false, rules - ) + + mlp_val_vectors, mlp_val_labels = get_mlp_data(model, abducer, mapping, val_X_true, val_X_false, rules) # Get MLP validation result mlp_val_data = BasicDataset(mlp_val_vectors, mlp_val_labels) @@ -306,7 +295,6 @@ def validation( batch_size=64, shuffle=True, ) - accuracy = mlp_model.val(mlp_val_data_loader) if accuracy > best_accuracy: @@ -314,41 +302,33 @@ def validation( return best_accuracy -def train_with_rule( - model, - abducer, - train_data, - val_data, - select_num=10, - recorder=None -): +def train_with_rule(model, abducer, train_data, val_data, epochs=50, select_num=10, verbose=-1): train_X = train_data val_X = val_data min_len = 5 - max_len = 8 + max_len = 18 # Start training / for each length of equations for equation_len in range(min_len, max_len): - INFO("============== equation_len:%d ================" % (equation_len)) + INFO("============== equation_len: %d-%d ================" % (equation_len, equation_len + 1)) train_X_true = train_X[1][equation_len] train_X_false = train_X[0][equation_len] val_X_true = val_X[1][equation_len] val_X_false = val_X[0][equation_len] + train_X_true.extend(train_X[1][equation_len + 1]) train_X_false.extend(train_X[0][equation_len + 1]) val_X_true.extend(val_X[1][equation_len + 1]) val_X_false.extend(val_X[0][equation_len + 1]) - condition_cnt = 0 + condition_cnt = 0 while True: # Abduce and train NN - consistent_acc, char_acc, mapping = abduce_and_train( - model, abducer, train_X_true, select_num - ) + consistent_acc, char_acc, mapping = abduce_and_train(model, abducer, train_X_true, select_num) if consistent_acc == 0: continue - + # Test if we can use mlp to evaluate if consistent_acc >= 0.9 and char_acc >= 0.9: condition_cnt += 1 @@ -357,37 +337,18 @@ def train_with_rule( # The condition has been satisfied continuously five times if condition_cnt >= 5: - best_accuracy = validation( - model, - abducer, - mapping, - train_X_true, - train_X_false, - val_X_true, - val_X_false, - recorder, - ) - - INFO("best_accuracy is %f" % (best_accuracy)) - + # Try to abduce rules in `validation` + best_accuracy = validation(model, abducer, mapping, train_X_true, train_X_false, val_X_true, val_X_false) + INFO('best_accuracy is %f' %(best_accuracy)) # decide next course or restart - if best_accuracy > 0.86: - torch.save( - model.cls_list[0].model.state_dict(), - "./weights/train_weights_%d.pth" % equation_len, - ) + if best_accuracy > 0.85: + torch.save(model.cls_list[0].model.state_dict(), "./weights/weights_%d.pth" % equation_len) break else: if equation_len == min_len: - model.cls_list[0].model.load_state_dict( - torch.load("./weights/pretrain_weights.pth") - ) + model.cls_list[0].model.load_state_dict(torch.load("./weights/pretrain_weights.pth")) else: - model.cls_list[0].model.load_state_dict( - torch.load( - "./weights/train_weights_%d.pth" % (equation_len - 1) - ) - ) + model.cls_list[0].model.load_state_dict(torch.load("./weights/weights_%d.pth" % (equation_len - 1))) condition_cnt = 0 return model From d7d854c966e749508c115657ae0af7ab27b771ee Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 20 Feb 2023 14:44:54 +0800 Subject: [PATCH 130/601] Add `get_final_rules` --- framework_hed.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/framework_hed.py b/framework_hed.py index 36159da..c1be4f8 100644 --- a/framework_hed.py +++ b/framework_hed.py @@ -299,7 +299,17 @@ def validation(model, abducer, mapping, train_X_true, train_X_false, val_X_true, if accuracy > best_accuracy: best_accuracy = accuracy - return best_accuracy + return best_accuracy, rules + +def get_final_rules(rules): + all_rule_dict = {} + rule_cnt = 0 + for rule in rules: + for r in rule: + all_rule_dict[r] = 1 if r not in all_rule_dict else all_rule_dict[r] + 1 + rule_dict = {rule: cnt for rule, cnt in all_rule_dict.items() if cnt >= 5} + rule_dict + return rule_dict def train_with_rule(model, abducer, train_data, val_data, epochs=50, select_num=10, verbose=-1): @@ -338,10 +348,11 @@ def train_with_rule(model, abducer, train_data, val_data, epochs=50, select_num= # The condition has been satisfied continuously five times if condition_cnt >= 5: # Try to abduce rules in `validation` - best_accuracy = validation(model, abducer, mapping, train_X_true, train_X_false, val_X_true, val_X_false) + best_accuracy, rules = validation(model, abducer, mapping, train_X_true, train_X_false, val_X_true, val_X_false) INFO('best_accuracy is %f' %(best_accuracy)) # decide next course or restart if best_accuracy > 0.85: + final_rules = get_final_rules(rules) torch.save(model.cls_list[0].model.state_dict(), "./weights/weights_%d.pth" % equation_len) break else: @@ -351,7 +362,7 @@ def train_with_rule(model, abducer, train_data, val_data, epochs=50, select_num= model.cls_list[0].model.load_state_dict(torch.load("./weights/weights_%d.pth" % (equation_len - 1))) condition_cnt = 0 - return model + return model, final_rules if __name__ == "__main__": From 410796c7405a52fcaed91b1eb8c17386d6d3e4ea Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 20 Feb 2023 14:45:40 +0800 Subject: [PATCH 131/601] Add `get_final_rules` --- framework_hed.py | 1 - 1 file changed, 1 deletion(-) diff --git a/framework_hed.py b/framework_hed.py index c1be4f8..ab08e58 100644 --- a/framework_hed.py +++ b/framework_hed.py @@ -308,7 +308,6 @@ def get_final_rules(rules): for r in rule: all_rule_dict[r] = 1 if r not in all_rule_dict else all_rule_dict[r] + 1 rule_dict = {rule: cnt for rule, cnt in all_rule_dict.items() if cnt >= 5} - rule_dict return rule_dict From 1eafe55c713c72adfb9714b660ea040735c72283 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 20 Feb 2023 14:47:02 +0800 Subject: [PATCH 132/601] Update framework_hed.py --- framework_hed.py | 1 - 1 file changed, 1 deletion(-) diff --git a/framework_hed.py b/framework_hed.py index ab08e58..082ceea 100644 --- a/framework_hed.py +++ b/framework_hed.py @@ -303,7 +303,6 @@ def validation(model, abducer, mapping, train_X_true, train_X_false, val_X_true, def get_final_rules(rules): all_rule_dict = {} - rule_cnt = 0 for rule in rules: for r in rule: all_rule_dict[r] = 1 if r not in all_rule_dict else all_rule_dict[r] + 1 From 680e9d42b684050d37d6a75a6e6b53080bafe811 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 20 Feb 2023 15:12:10 +0800 Subject: [PATCH 133/601] Update framework_hed.py --- framework_hed.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/framework_hed.py b/framework_hed.py index 082ceea..974561c 100644 --- a/framework_hed.py +++ b/framework_hed.py @@ -306,8 +306,9 @@ def get_final_rules(rules): for rule in rules: for r in rule: all_rule_dict[r] = 1 if r not in all_rule_dict else all_rule_dict[r] + 1 - rule_dict = {rule: cnt for rule, cnt in all_rule_dict.items() if cnt >= 5} - return rule_dict + rule_dict = {rule: cnt for rule, cnt in all_rule_dict.items() if cnt > 5} + final_rules = [r for r in rule_dict] + return final_rules def train_with_rule(model, abducer, train_data, val_data, epochs=50, select_num=10, verbose=-1): @@ -315,7 +316,7 @@ def train_with_rule(model, abducer, train_data, val_data, epochs=50, select_num= val_X = val_data min_len = 5 - max_len = 18 + max_len = 8 # Start training / for each length of equations for equation_len in range(min_len, max_len): @@ -359,7 +360,9 @@ def train_with_rule(model, abducer, train_data, val_data, epochs=50, select_num= else: model.cls_list[0].model.load_state_dict(torch.load("./weights/weights_%d.pth" % (equation_len - 1))) condition_cnt = 0 - + + INFO('final_rules: ', final_rules) + return model, final_rules From 63da2da61d3df898f8e43723b6ab63fc91d00440 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 22 Feb 2023 10:08:32 +0800 Subject: [PATCH 134/601] Update example.py --- example.py | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/example.py b/example.py index a81b51d..72c0bca 100644 --- a/example.py +++ b/example.py @@ -11,28 +11,25 @@ # ================================================================# from utils.plog import logger, INFO -from utils.utils import copy_state_dict import torch.nn as nn import torch -from models.nn import LeNet5, SymbolNet, SymbolNetAutoencoder +from models.nn import LeNet5, SymbolNet from models.basic_model import BasicModel, BasicDataset from models.wabl_models import DecisionTree, WABLBasicModel from multiprocessing import Pool -import os from abducer.abducer_base import AbducerBase from abducer.kb import add_KB, HWF_KB, HED_prolog_KB from datasets.mnist_add.get_mnist_add import get_mnist_add from datasets.hwf.get_hwf import get_hwf -from datasets.hed.get_hed import get_hed, split_equation, get_pretrain_data -import framework_hed +from datasets.hed.get_hed import get_hed, split_equation +import framework def run_test(): # kb = add_KB(True) - # kb = HWF_KB(True) # abducer = AbducerBase(kb) @@ -46,25 +43,10 @@ def run_test(): test_data = get_hed(train=False) # cls = LeNet5(num_classes=len(kb.pseudo_label_list), image_size=(train_data[0][0][0].shape[1:])) - cls_autoencoder = SymbolNetAutoencoder(num_classes=len(kb.pseudo_label_list)) cls = SymbolNet(num_classes=len(kb.pseudo_label_list)) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - if not os.path.exists("./weights/pretrain_weights.pth"): - INFO("Pretrain Start") - pretrain_data_X, pretrain_data_Y = get_pretrain_data(['0', '1', '10', '11']) - pretrain_data = BasicDataset(pretrain_data_X, pretrain_data_Y) - - criterion = nn.MSELoss() - optimizer = torch.optim.RMSprop(cls_autoencoder.parameters(), lr=0.001, alpha=0.9, weight_decay=1e-6) - - pretrain_model = BasicModel(cls_autoencoder, criterion, optimizer, device, save_interval=1, save_dir=recorder.save_dir, num_epochs=10, recorder=recorder) - framework_hed.pretrain(pretrain_model, pretrain_data) - torch.save(cls_autoencoder.base_model.state_dict(), "./weights/pretrain_weights.pth") - cls.load_state_dict(cls_autoencoder.base_model.state_dict()) - - else: - cls.load_state_dict(torch.load("./weights/pretrain_weights.pth")) + framework.hed_pretrain(kb, cls, recorder) criterion = nn.CrossEntropyLoss() optimizer = torch.optim.RMSprop(cls.parameters(), lr=0.001, weight_decay=1e-6) @@ -80,8 +62,8 @@ def run_test(): # train_data = get_hwf(train = True, get_pseudo_label = True) # test_data = get_hwf(train = False, get_pseudo_label = True) - framework_hed.train_with_rule(model, abducer, train_data, val_data, select_num=10, verbose=1) - # recorder.print(res) + model, mapping = framework.train_with_rule(model, abducer, train_data, val_data, select_num=10, min_len=5, max_len=8) + framework.hed_test(model, abducer, mapping, train_data, test_data, min_len=5, max_len=8) recorder.dump() return True From 4170a1fe7d7ff97c572b00a190fd422c388bfd55 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 22 Feb 2023 10:09:16 +0800 Subject: [PATCH 135/601] Update example.py --- example.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/example.py b/example.py index 72c0bca..30c50fc 100644 --- a/example.py +++ b/example.py @@ -24,7 +24,7 @@ from abducer.kb import add_KB, HWF_KB, HED_prolog_KB from datasets.mnist_add.get_mnist_add import get_mnist_add from datasets.hwf.get_hwf import get_hwf from datasets.hed.get_hed import get_hed, split_equation -import framework +import framework_hed def run_test(): @@ -46,7 +46,7 @@ def run_test(): cls = SymbolNet(num_classes=len(kb.pseudo_label_list)) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - framework.hed_pretrain(kb, cls, recorder) + framework_hed.hed_pretrain(kb, cls, recorder) criterion = nn.CrossEntropyLoss() optimizer = torch.optim.RMSprop(cls.parameters(), lr=0.001, weight_decay=1e-6) @@ -62,8 +62,8 @@ def run_test(): # train_data = get_hwf(train = True, get_pseudo_label = True) # test_data = get_hwf(train = False, get_pseudo_label = True) - model, mapping = framework.train_with_rule(model, abducer, train_data, val_data, select_num=10, min_len=5, max_len=8) - framework.hed_test(model, abducer, mapping, train_data, test_data, min_len=5, max_len=8) + model, mapping = framework_hed.train_with_rule(model, abducer, train_data, val_data, select_num=10, min_len=5, max_len=8) + framework_hed.hed_test(model, abducer, mapping, train_data, test_data, min_len=5, max_len=8) recorder.dump() return True From dd777ed4336494ab35352c1363565c4f94c23cb3 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 22 Feb 2023 10:09:58 +0800 Subject: [PATCH 136/601] Add test_hed --- framework_hed.py | 260 ++++++++++++++++++++++++++--------------------- 1 file changed, 143 insertions(+), 117 deletions(-) diff --git a/framework_hed.py b/framework_hed.py index 974561c..e464ed0 100644 --- a/framework_hed.py +++ b/framework_hed.py @@ -11,18 +11,17 @@ # ================================================================# import pickle as pk -import math import torch import torch.nn as nn import numpy as np +import os from utils.plog import INFO, DEBUG, clocker -from utils.utils import flatten, reform_idx, block_sample -from utils.utils import copy_state_dict +from utils.utils import flatten, reform_idx, block_sample, gen_mappings, mapping_res, remapping_res -from sklearn.linear_model import LogisticRegression -from models.nn import MLP +from models.nn import MLP, SymbolNetAutoencoder from models.basic_model import BasicModel, BasicDataset +from datasets.hed.get_hed import get_pretrain_data def result_statistics(pred_Z, Z, Y, logic_forward, char_acc_flag): result = {} @@ -99,72 +98,54 @@ def train(model, abducer, train_data, test_data, epochs=50, sample_num=-1, verbo return res +def hed_pretrain(kb, cls, recorder): + cls_autoencoder = SymbolNetAutoencoder(num_classes=len(kb.pseudo_label_list)) + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + if not os.path.exists("./weights/pretrain_weights.pth"): + INFO("Pretrain Start") + pretrain_data_X, pretrain_data_Y = get_pretrain_data(['0', '1', '10', '11']) + pretrain_data = BasicDataset(pretrain_data_X, pretrain_data_Y) + pretrain_data_loader = torch.utils.data.DataLoader(pretrain_data, batch_size=64, shuffle=True) + + criterion = nn.MSELoss() + optimizer = torch.optim.RMSprop(cls_autoencoder.parameters(), lr=0.001, alpha=0.9, weight_decay=1e-6) -def pretrain(pretrain_model, pretrain_data): - INFO("Pretrain Start") - pretrain_data_loader = torch.utils.data.DataLoader( - pretrain_data, - batch_size=64, - shuffle=True, - num_workers=2, - ) - pretrain_model.fit(pretrain_data_loader) + pretrain_model = BasicModel(cls_autoencoder, criterion, optimizer, device, save_interval=1, save_dir=recorder.save_dir, num_epochs=10, recorder=recorder) + pretrain_model.fit(pretrain_data_loader) + torch.save(cls_autoencoder.base_model.state_dict(), "./weights/pretrain_weights.pth") + cls.load_state_dict(cls_autoencoder.base_model.state_dict()) + + else: + cls.load_state_dict(torch.load("./weights/pretrain_weights.pth")) -def get_char_acc(model, X, consistent_pred_res): - print('Abduced labels: ', flatten(consistent_pred_res)) - pred_res = flatten(model.predict(X)['cls']) - print('Current model\'s output:', pred_res) +def get_char_acc(model, X, consistent_pred_res, mapping): + original_pred_res = model.predict(X)['cls'] + pred_res = flatten(mapping_res(original_pred_res, mapping)) + INFO('Current model\'s output:', pred_res) + INFO('Abduced labels: ', flatten(consistent_pred_res)) assert len(pred_res) == len(flatten(consistent_pred_res)) return sum([pred_res[idx] == flatten(consistent_pred_res)[idx] for idx in range(len(pred_res))]) / len(pred_res) -def gen_mappings(chars, symbs): - n_char = len(chars) - n_symbs = len(symbs) - if n_char != n_symbs: - print('Characters and symbols size dosen\'t match.') - return - from itertools import permutations - mappings = [] - # returned mappings - perms = permutations(symbs) - for p in perms: - mappings.append(dict(zip(chars, list(p)))) - return mappings - -def map_res(pred_res, m): - for i in range(len(pred_res)): - for j in range(len(pred_res[i])): - pred_res[i][j] = m[pred_res[i][j]] - return pred_res - -def map_res(original_pred_res, m): - return [[m[symbol] for symbol in formula] for formula in original_pred_res] - -def abduce_and_train(model, abducer, train_X_true, select_num): + +def abduce_and_train(model, abducer, mapping, train_X_true, select_num): select_idx = np.random.randint(len(train_X_true), size=select_num) X = [] for idx in select_idx: X.append(train_X_true[idx]) - pred_res = model.predict(X)['cls'] + original_pred_res = model.predict(X)['cls'] - maps = gen_mappings(['+', '=', 0, 1],['+', '=', 0, 1]) + if mapping == None: + mappings = gen_mappings(['+', '=', 0, 1],['+', '=', 0, 1]) + else: + mappings = [mapping] consistent_idx = [] consistent_pred_res = [] - import copy - - original_pred_res = copy.deepcopy(pred_res) - mapping = None - - for m in maps: - pred_res = map_res(original_pred_res, m) - remapping = {} - for key, value in m.items(): - remapping[value] = key - + for m in mappings: + pred_res = mapping_res(original_pred_res, m) max_abduce_num = 20 solution = abducer.zoopt_get_solution(pred_res, [1] * len(pred_res), max_abduce_num) all_address_flag = reform_idx(solution, pred_res) @@ -177,28 +158,38 @@ def abduce_and_train(model, abducer, train_X_true, select_num): candidate = abducer.kb.address_by_idx([pred_res[idx]], 1, address_idx, True) if len(candidate) > 0: consistent_idx_tmp.append(idx) - consistent_pred_res_tmp.append([remapping[symbol] for symbol in candidate[0][0]]) + consistent_pred_res_tmp.append(candidate[0][0]) if len(consistent_idx_tmp) > len(consistent_idx): consistent_idx = consistent_idx_tmp consistent_pred_res = consistent_pred_res_tmp - mapping = m + if len(mappings) > 1: + mapping = m if len(consistent_idx) == 0: return 0, 0, None - INFO("Consistent predict results are: ", map_res(consistent_pred_res, mapping)) - INFO('Train pool size is:', len(flatten(consistent_pred_res))) + if len(mappings) > 1: + INFO('Final mapping is: ', mapping) + INFO('Train pool size is:', len(flatten(consistent_pred_res))) INFO("Start to use abduced pseudo label to train model...") - model.train([X[idx] for idx in consistent_idx], consistent_pred_res) + model.train([X[idx] for idx in consistent_idx], remapping_res(consistent_pred_res, mapping)) consistent_acc = len(consistent_idx) / select_num - char_acc = get_char_acc(model, [X[idx] for idx in consistent_idx], consistent_pred_res) + char_acc = get_char_acc(model, [X[idx] for idx in consistent_idx], consistent_pred_res, mapping) INFO('consistent_acc is %s, char_acc is %s' % (consistent_acc, char_acc)) return consistent_acc, char_acc, mapping +def output_rules(rules): + all_rule_dict = {} + for rule in rules: + for r in rule: + all_rule_dict[r] = 1 if r not in all_rule_dict else all_rule_dict[r] + 1 + rule_dict = {rule: cnt for rule, cnt in all_rule_dict.items()}# if cnt >= 5} + return rule_dict + def get_rules_from_data(model, abducer, mapping, train_X_true, samples_per_rule, logic_output_dim): rules = [] for _ in range(logic_output_dim): @@ -208,7 +199,7 @@ def get_rules_from_data(model, abducer, mapping, train_X_true, samples_per_rule, for idx in select_idx: X.append(train_X_true[idx]) original_pred_res = model.predict(X)['cls'] - pred_res = map_res(original_pred_res, mapping) + pred_res = mapping_res(original_pred_res, mapping) consistent_idx = [] consistent_pred_res = [] @@ -222,15 +213,12 @@ def get_rules_from_data(model, abducer, mapping, train_X_true, samples_per_rule, if rule != None: break rules.append(rule) - - INFO('Learned rules from data:') - INFO(rules) return rules def get_mlp_vector(model, abducer, mapping, X, rules): original_pred_res = model.predict([X])['cls'] - pred_res = map_res(original_pred_res, mapping) + pred_res = mapping_res(original_pred_res, mapping) vector = [] for rule in rules: if abducer.kb.consist_rule(pred_res, rule): @@ -249,25 +237,28 @@ def get_mlp_data(model, abducer, mapping, X_true, X_false, rules): for X in X_false: mlp_vectors.append(get_mlp_vector(model, abducer, mapping, X, rules)) mlp_labels.append(0) - return np.array(mlp_vectors, dtype=np.float32), np.array(mlp_labels, dtype=np.int64) +def get_all_mlp_data(model, abducer, mapping, X_true, X_false, rules, min_len, max_len): + for equation_len in range(min_len, max_len + 1): + mlp_vectors, mlp_labels = get_mlp_data(model, abducer, mapping, X_true[equation_len], X_false[equation_len], rules) + if equation_len == min_len: + all_mlp_vectors = mlp_vectors + all_mlp_labels = mlp_labels + else: + all_mlp_vectors = np.concatenate((all_mlp_vectors, mlp_vectors)) + all_mlp_labels = np.concatenate((all_mlp_labels, mlp_labels)) + return all_mlp_vectors, all_mlp_labels -def validation(model, abducer, mapping, train_X_true, train_X_false, val_X_true, val_X_false): - INFO("Now checking if we can go to next course") - samples_per_rule = 3 - logic_output_dim = 50 - rules = get_rules_from_data(model, abducer, mapping, train_X_true, samples_per_rule, logic_output_dim) +def validation(model, abducer, mapping, logic_output_dim, rules, train_X_true, train_X_false, val_X_true, val_X_false): mlp_train_vectors, mlp_train_labels = get_mlp_data(model, abducer, mapping, train_X_true, train_X_false, rules) - - idx = np.array(list(range(len(mlp_train_labels)))) - np.random.shuffle(idx) - mlp_train_vectors = mlp_train_vectors[idx] - mlp_train_labels = mlp_train_labels[idx] - + mlp_train_data = BasicDataset(mlp_train_vectors, mlp_train_labels) + + mlp_val_vectors, mlp_val_labels = get_mlp_data(model, abducer, mapping, val_X_true, val_X_false, rules) + mlp_val_data = BasicDataset(mlp_val_vectors, mlp_val_labels) + best_accuracy = 0 - # Try three times to find the best mlp for _ in range(3): INFO("Training mlp...") @@ -277,46 +268,29 @@ def validation(model, abducer, mapping, train_X_true, train_X_false, val_X_true, device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") mlp_model = BasicModel(mlp, criterion, optimizer, device, batch_size=128, num_epochs=60) - mlp_train_data = BasicDataset(mlp_train_vectors, mlp_train_labels) - mlp_train_data_loader = torch.utils.data.DataLoader( - mlp_train_data, - batch_size=128, - shuffle=True - ) + mlp_train_data_loader = torch.utils.data.DataLoader(mlp_train_data, batch_size=128, shuffle=True) + loss = mlp_model.fit(mlp_train_data_loader) - INFO("mlp training loss is %f" % loss) + INFO("mlp training final loss is %f" % loss) - mlp_val_vectors, mlp_val_labels = get_mlp_data(model, abducer, mapping, val_X_true, val_X_false, rules) - - # Get MLP validation result - mlp_val_data = BasicDataset(mlp_val_vectors, mlp_val_labels) - mlp_val_data_loader = torch.utils.data.DataLoader( - mlp_val_data, - batch_size=64, - shuffle=True, - ) + mlp_val_data_loader = torch.utils.data.DataLoader(mlp_val_data, batch_size=64, shuffle=True) accuracy = mlp_model.val(mlp_val_data_loader) if accuracy > best_accuracy: best_accuracy = accuracy - return best_accuracy, rules + return best_accuracy + + + -def get_final_rules(rules): - all_rule_dict = {} - for rule in rules: - for r in rule: - all_rule_dict[r] = 1 if r not in all_rule_dict else all_rule_dict[r] + 1 - rule_dict = {rule: cnt for rule, cnt in all_rule_dict.items() if cnt > 5} - final_rules = [r for r in rule_dict] - return final_rules -def train_with_rule(model, abducer, train_data, val_data, epochs=50, select_num=10, verbose=-1): +def train_with_rule(model, abducer, train_data, val_data, select_num=10, min_len=5, max_len=8): train_X = train_data val_X = val_data - - min_len = 5 - max_len = 8 + + logic_output_dim = 50 + samples_per_rule = 3 # Start training / for each length of equations for equation_len in range(min_len, max_len): @@ -333,8 +307,11 @@ def train_with_rule(model, abducer, train_data, val_data, epochs=50, select_num= condition_cnt = 0 while True: + if equation_len == min_len: + mapping = None + # Abduce and train NN - consistent_acc, char_acc, mapping = abduce_and_train(model, abducer, train_X_true, select_num) + consistent_acc, char_acc, mapping = abduce_and_train(model, abducer, mapping, train_X_true, select_num) if consistent_acc == 0: continue @@ -346,12 +323,13 @@ def train_with_rule(model, abducer, train_data, val_data, epochs=50, select_num= # The condition has been satisfied continuously five times if condition_cnt >= 5: - # Try to abduce rules in `validation` - best_accuracy, rules = validation(model, abducer, mapping, train_X_true, train_X_false, val_X_true, val_X_false) - INFO('best_accuracy is %f' %(best_accuracy)) + INFO("Now checking if we can go to next course") + rules = get_rules_from_data(model, abducer, mapping, train_X_true, samples_per_rule, logic_output_dim) + INFO('Learned rules from data:', output_rules(rules)) + best_accuracy = validation(model, abducer, mapping, logic_output_dim, rules, train_X_true, train_X_false, val_X_true, val_X_false) + INFO('best_accuracy is %f\n' %(best_accuracy)) # decide next course or restart if best_accuracy > 0.85: - final_rules = get_final_rules(rules) torch.save(model.cls_list[0].model.state_dict(), "./weights/weights_%d.pth" % equation_len) break else: @@ -360,11 +338,59 @@ def train_with_rule(model, abducer, train_data, val_data, epochs=50, select_num= else: model.cls_list[0].model.load_state_dict(torch.load("./weights/weights_%d.pth" % (equation_len - 1))) condition_cnt = 0 - - INFO('final_rules: ', final_rules) - - return model, final_rules + INFO('Reload Model and retrain') + + return model, mapping +def hed_test(model, abducer, mapping, train_data, test_data, min_len=5, max_len=8): + train_X = train_data + test_X = test_data + + # Calcualte how many equations should be selected in each length + # for each length, there are select_equation_cnt[equation_len] rules + print("Now begin to train final mlp model") + select_equation_cnt = [] + len_cnt = max_len - min_len + 1 + logic_output_dim = 50 + select_equation_cnt += [0] * min_len + if logic_output_dim % len_cnt == 0: + select_equation_cnt += [logic_output_dim // len_cnt] * len_cnt + else: + select_equation_cnt += [logic_output_dim // len_cnt] * len_cnt + select_equation_cnt[-1] += logic_output_dim % len_cnt + assert sum(select_equation_cnt) == logic_output_dim + + # Abduce rules + rules = [] + samples_per_rule = 3 + for equation_len in range(min_len, max_len + 1): + equation_rules = get_rules_from_data(model, abducer, mapping, train_X[1][equation_len], samples_per_rule, select_equation_cnt[equation_len]) + rules.extend(equation_rules) + INFO('Learned rules from data:', output_rules(rules)) + + mlp_train_vectors, mlp_train_labels = get_all_mlp_data(model, abducer, mapping, train_X[1], train_X[0], rules, min_len, max_len) + mlp_train_data = BasicDataset(mlp_train_vectors, mlp_train_labels) + + # Try three times to find the best mlp + for _ in range(3): + mlp = MLP(input_dim=logic_output_dim) + criterion = nn.CrossEntropyLoss() + optimizer = torch.optim.Adam(mlp.parameters(), lr=0.01, betas=(0.9, 0.999)) + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + mlp_model = BasicModel(mlp, criterion, optimizer, device, batch_size=128, num_epochs=60) + mlp_train_data_loader = torch.utils.data.DataLoader(mlp_train_data, batch_size=128, shuffle=True) + + loss = mlp_model.fit(mlp_train_data_loader) + INFO("mlp training final loss is %f" % loss) + + for equation_len in range(5, 27): + mlp_test_vectors, mlp_test_labels = get_mlp_data(model, abducer, mapping, test_X[1][equation_len], test_X[0][equation_len], rules) + mlp_test_data = BasicDataset(mlp_test_vectors, mlp_test_labels) + mlp_test_data_loader = torch.utils.data.DataLoader(mlp_test_data, batch_size=64, shuffle=True) + accuracy = mlp_model.val(mlp_test_data_loader) + INFO("The accuracy of testing length %d equations is: %f" % (equation_len, accuracy)) + INFO("\n") if __name__ == "__main__": pass From ae472fccc9341c93ad3677239ea46222ab7d4b57 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 22 Feb 2023 10:10:42 +0800 Subject: [PATCH 137/601] Add test_hed --- utils/utils.py | 69 +++++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 57dea31..f4db6f2 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -2,16 +2,10 @@ import numpy as np from utils.plog import INFO from collections import OrderedDict - # for multiple predictions, modify from `learn_add.py` def flatten(l): - return ( - [item for sublist in l for item in flatten(sublist)] - if isinstance(l, list) - else [l] - ) - - + return [item for sublist in l for item in flatten(sublist)] if isinstance(l, list) else [l] + # for multiple predictions, modify from `learn_add.py` def reform_idx(flatten_pred_res, save_pred_res): re = [] @@ -26,6 +20,22 @@ def reform_idx(flatten_pred_res, save_pred_res): i = i + j return re +def hamming_dist(A, B): + B = np.array(B) + A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) + return np.sum(A != B, axis = 1) + +def confidence_dist(A, B): + B = np.array(B) + A = np.clip(A, 1e-9, 1) + A = np.expand_dims(A, axis=0) + A = A.repeat(axis=0, repeats=(len(B))) + rows = np.array(range(len(B))) + rows = np.expand_dims(rows, axis = 1).repeat(axis = 1, repeats = len(B[0])) + cols = np.array(range(len(B[0]))) + cols = np.expand_dims(cols, axis = 0).repeat(axis = 0, repeats = len(B)) + return 1 - np.prod(A[rows, cols, B], axis = 1) + def block_sample(X, Z, Y, sample_num, epoch_idx): part_num = len(X) // sample_num @@ -40,28 +50,25 @@ def block_sample(X, Z, Y, sample_num, epoch_idx): return X, Z, Y -def hamming_dist(A, B): - B = np.array(B) - A = np.expand_dims(A, axis=0).repeat(axis=0, repeats=(len(B))) - return np.sum(A != B, axis=1) - - -def confidence_dist(A, B): - B = np.array(B) - A = np.clip(A, 1e-9, 1) - A = np.expand_dims(A, axis=0) - A = A.repeat(axis=0, repeats=(len(B))) - rows = np.array(range(len(B))) - rows = np.expand_dims(rows, axis=1).repeat(axis=1, repeats=len(B[0])) - cols = np.array(range(len(B[0]))) - cols = np.expand_dims(cols, axis=0).repeat(axis=0, repeats=len(B)) - return 1 - np.prod(A[rows, cols, B], axis=1) +def gen_mappings(chars, symbs): + n_char = len(chars) + n_symbs = len(symbs) + if n_char != n_symbs: + print('Characters and symbols size dosen\'t match.') + return + from itertools import permutations + mappings = [] + # returned mappings + perms = permutations(symbs) + for p in perms: + mappings.append(dict(zip(chars, list(p)))) + return mappings +def mapping_res(original_pred_res, m): + return [[m[symbol] for symbol in formula] for formula in original_pred_res] -def copy_state_dict(state_dict): - new_state_dict = OrderedDict() - for k, v in state_dict.items(): - if k.startswith('base_model'): - name = ".".join(k.split(".")[1:]) - new_state_dict[name] = v - return new_state_dict +def remapping_res(pred_res, m): + remapping = {} + for key, value in m.items(): + remapping[value] = key + return [[remapping[symbol] for symbol in formula] for formula in pred_res] From 121827f8ba248603e8f63b5a1d6bbe5b86376208 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 22 Feb 2023 14:58:05 +0800 Subject: [PATCH 138/601] Update kb.py --- abducer/kb.py | 172 ++++++++++++-------------------------------------- 1 file changed, 42 insertions(+), 130 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 04a9f68..959b4ac 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -43,29 +43,16 @@ class KBBase(ABC): def address(self, address_num, pred_res, key, multiple_predictions=False): new_candidates = [] if not multiple_predictions: - address_idx_list = list( - combinations(list(range(len(pred_res))), address_num) - ) + address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) else: - address_idx_list = list( - combinations(list(range(len(flatten(pred_res)))), address_num) - ) + address_idx_list = list(combinations(list(range(len(flatten(pred_res)))), address_num)) for address_idx in address_idx_list: - candidates = self.address_by_idx( - pred_res, key, address_idx, multiple_predictions - ) + candidates = self.address_by_idx(pred_res, key, address_idx, multiple_predictions) new_candidates += candidates return new_candidates - def abduction( - self, - pred_res, - key, - max_address_num, - require_more_address, - multiple_predictions=False, - ): + def abduction(self, pred_res, key, max_address_num, require_more_address, multiple_predictions=False): candidates = [] for address_num in range(len(pred_res) + 1): @@ -73,9 +60,7 @@ class KBBase(ABC): if abs(self.logic_forward(pred_res) - key) <= 1e-3: candidates.append(pred_res) else: - new_candidates = self.address( - address_num, pred_res, key, multiple_predictions - ) + new_candidates = self.address(address_num, pred_res, key, multiple_predictions) candidates += new_candidates if len(candidates) > 0: @@ -85,14 +70,10 @@ class KBBase(ABC): if address_num >= max_address_num: return [], 0, 0 - for address_num in range( - min_address_num + 1, min_address_num + require_more_address + 1 - ): + for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): if address_num > max_address_num: return candidates, min_address_num, address_num - 1 - new_candidates = self.address( - address_num, pred_res, key, multiple_predictions - ) + new_candidates = self.address(address_num, pred_res, key, multiple_predictions) candidates += new_candidates return candidates, min_address_num, address_num @@ -117,9 +98,7 @@ class ClsKB(KBBase): else: self.all_address_candidate_dict = {} for address_num in range(max(self.len_list) + 1): - self.all_address_candidate_dict[address_num] = list( - product(self.pseudo_label_list, repeat=address_num) - ) + self.all_address_candidate_dict[address_num] = list(product(self.pseudo_label_list, repeat=address_num)) # For parallel version of _get_GKB def _get_XY_list(self, args): @@ -164,26 +143,11 @@ class ClsKB(KBBase): def logic_forward(self): pass - def abduce_candidates( - self, - pred_res, - key, - max_address_num=-1, - require_more_address=0, - multiple_predictions=False, - ): + def abduce_candidates(self, pred_res, key, max_address_num=-1, require_more_address=0, multiple_predictions=False): if self.GKB_flag: - return self.abduce_from_GKB( - pred_res, key, max_address_num, require_more_address - ) + return self.abduce_from_GKB(pred_res, key, max_address_num, require_more_address) else: - return self.abduction( - pred_res, - key, - max_address_num, - require_more_address, - multiple_predictions, - ) + return self.abduction(pred_res, key, max_address_num, require_more_address, multiple_predictions) def abduce_from_GKB(self, pred_res, key, max_address_num, require_more_address): if self.base == {} or len(pred_res) not in self.len_list: @@ -247,24 +211,7 @@ class add_KB(ClsKB): class HWF_KB(ClsKB): def __init__( - self, - GKB_flag=False, - pseudo_label_list=[ - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "+", - "-", - "times", - "div", - ], - len_list=[1, 3, 5, 7], + self, GKB_flag=False, pseudo_label_list=['1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', 'times', 'div'], len_list=[1, 3, 5, 7] ): super().__init__(GKB_flag, pseudo_label_list, len_list) @@ -272,19 +219,9 @@ class HWF_KB(ClsKB): if len(formula) % 2 == 0: return False for i in range(len(formula)): - if i % 2 == 0 and formula[i] not in [ - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - ]: + if i % 2 == 0 and formula[i] not in ['1', '2', '3', '4', '5', '6', '7', '8', '9']: return False - if i % 2 != 0 and formula[i] not in ["+", "-", "times", "div"]: + if i % 2 != 0 and formula[i] not in ['+', '-', 'times', 'div']: return False return True @@ -292,22 +229,22 @@ class HWF_KB(ClsKB): if not self.valid_candidate(formula): return np.inf mapping = { - "1": "1", - "2": "2", - "3": "3", - "4": "4", - "5": "5", - "6": "6", - "7": "7", - "8": "8", - "9": "9", - "+": "+", - "-": "-", - "times": "*", - "div": "/", + '1': '1', + '2': '2', + '3': '3', + '4': '4', + '5': '5', + '6': '6', + '7': '7', + '8': '8', + '9': '9', + '+': '+', + '-': '-', + 'times': '*', + 'div': '/', } formula = [mapping[f] for f in formula] - return round(eval("".join(formula)), 2) + return round(eval(''.join(formula)), 2) class prolog_KB(KBBase): @@ -319,12 +256,8 @@ class prolog_KB(KBBase): def logic_forward(self): pass - def abduce_candidates( - self, pred_res, key, max_address_num, require_more_address, multiple_predictions - ): - return self.abduction( - pred_res, key, max_address_num, require_more_address, multiple_predictions - ) + def abduce_candidates(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): + return self.abduction(pred_res, key, max_address_num, require_more_address, multiple_predictions) def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): candidates = [] @@ -332,9 +265,7 @@ class prolog_KB(KBBase): if not multiple_predictions: query_string = self.get_query_string(pred_res, key, address_idx) else: - query_string = self.get_query_string_need_flatten( - pred_res, key, address_idx - ) + query_string = self.get_query_string_need_flatten(pred_res, key, address_idx) if multiple_predictions: save_pred_res = pred_res @@ -358,28 +289,24 @@ class add_prolog_KB(prolog_KB): super().__init__(pseudo_label_list) for i in self.pseudo_label_list: self.prolog.assertz("pseudo_label(%s)" % i) - self.prolog.assertz( - "addition(Z1, Z2, Res) :- pseudo_label(Z1), pseudo_label(Z2), Res is Z1+Z2" - ) + self.prolog.assertz("addition(Z1, Z2, Res) :- pseudo_label(Z1), pseudo_label(Z2), Res is Z1+Z2") def logic_forward(self, nums): - return list(self.prolog.query("addition(%s, %s, Res)." % (nums[0], nums[1])))[ - 0 - ]["Res"] + return list(self.prolog.query("addition(%s, %s, Res)." % (nums[0], nums[1])))[0]['Res'] def get_query_string(self, pred_res, key, address_idx): query_string = "addition(" for idx, i in enumerate(pred_res): - tmp = "Z" + str(idx) + "," if idx in address_idx else str(i) + "," + tmp = 'Z' + str(idx) + ',' if idx in address_idx else str(i) + ',' query_string += tmp query_string += "%s)." % key return query_string class HED_prolog_KB(prolog_KB): - def __init__(self, pseudo_label_list=[0, 1, "+", "="]): + def __init__(self, pseudo_label_list=[0, 1, '+', '=']): super().__init__(pseudo_label_list) - self.prolog.consult("./datasets/hed/learn_add.pl") + self.prolog.consult('./datasets/hed/learn_add.pl') # corresponding to `con_sol is not None` in `consistent_score_mapped` within `learn_add.py` def logic_forward(self, exs): @@ -391,7 +318,7 @@ class HED_prolog_KB(prolog_KB): # add variables for prolog for idx in range(len(flatten_pred_res)): if idx in address_idx: - flatten_pred_res[idx] = "X" + str(idx) + flatten_pred_res[idx] = 'X' + str(idx) # unflatten new_pred_res = reform_idx(flatten_pred_res, pred_res) @@ -399,30 +326,15 @@ class HED_prolog_KB(prolog_KB): return query_string.replace("'", "").replace("+", "'+'").replace("=", "'='") def consist_rule(self, exs, rules): - consist = False - for rule in rules: - # print(rule) - if ( - len( - list( - self.prolog.query( - "consistent_inst_feature(%s, [%s])." % (exs, rule) - ) - ) - ) - != 0 - ): - consist = True - break - return consist + rules = str(rules).replace("\'","") + return len(list(self.prolog.query("eval_inst_feature(%s, %s)." % (exs, rules)))) != 0 def abduce_rules(self, pred_res): - prolog_result = list( - self.prolog.query("consistent_inst_feature(%s, X)." % pred_res) - ) + # print(pred_res) + prolog_result = list(self.prolog.query("consistent_inst_feature(%s, X)." % pred_res)) if len(prolog_result) == 0: return None - prolog_rules = prolog_result[0]["X"] + prolog_rules = prolog_result[0]['X'] rules = [] for rule in prolog_rules: rules.append(rule.value) From 54492a5a37effaa56554cd8ec95aab32b3093fb3 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 22 Feb 2023 14:58:27 +0800 Subject: [PATCH 139/601] Update framework_hed.py --- framework_hed.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/framework_hed.py b/framework_hed.py index e464ed0..3476462 100644 --- a/framework_hed.py +++ b/framework_hed.py @@ -122,8 +122,8 @@ def hed_pretrain(kb, cls, recorder): def get_char_acc(model, X, consistent_pred_res, mapping): original_pred_res = model.predict(X)['cls'] pred_res = flatten(mapping_res(original_pred_res, mapping)) - INFO('Current model\'s output:', pred_res) - INFO('Abduced labels: ', flatten(consistent_pred_res)) + INFO('Current model\'s output: ', pred_res) + INFO('Abduced labels: ', flatten(consistent_pred_res)) assert len(pred_res) == len(flatten(consistent_pred_res)) return sum([pred_res[idx] == flatten(consistent_pred_res)[idx] for idx in range(len(pred_res))]) / len(pred_res) @@ -218,7 +218,7 @@ def get_rules_from_data(model, abducer, mapping, train_X_true, samples_per_rule, def get_mlp_vector(model, abducer, mapping, X, rules): original_pred_res = model.predict([X])['cls'] - pred_res = mapping_res(original_pred_res, mapping) + pred_res = flatten(mapping_res(original_pred_res, mapping)) vector = [] for rule in rules: if abducer.kb.consist_rule(pred_res, rule): @@ -267,7 +267,7 @@ def validation(model, abducer, mapping, logic_output_dim, rules, train_X_true, t optimizer = torch.optim.Adam(mlp.parameters(), lr=0.01, betas=(0.9, 0.999)) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - mlp_model = BasicModel(mlp, criterion, optimizer, device, batch_size=128, num_epochs=60) + mlp_model = BasicModel(mlp, criterion, optimizer, device, batch_size=128, num_epochs=100) mlp_train_data_loader = torch.utils.data.DataLoader(mlp_train_data, batch_size=128, shuffle=True) loss = mlp_model.fit(mlp_train_data_loader) @@ -329,7 +329,7 @@ def train_with_rule(model, abducer, train_data, val_data, select_num=10, min_len best_accuracy = validation(model, abducer, mapping, logic_output_dim, rules, train_X_true, train_X_false, val_X_true, val_X_false) INFO('best_accuracy is %f\n' %(best_accuracy)) # decide next course or restart - if best_accuracy > 0.85: + if best_accuracy > 0.88: torch.save(model.cls_list[0].model.state_dict(), "./weights/weights_%d.pth" % equation_len) break else: @@ -378,7 +378,7 @@ def hed_test(model, abducer, mapping, train_data, test_data, min_len=5, max_len= optimizer = torch.optim.Adam(mlp.parameters(), lr=0.01, betas=(0.9, 0.999)) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - mlp_model = BasicModel(mlp, criterion, optimizer, device, batch_size=128, num_epochs=60) + mlp_model = BasicModel(mlp, criterion, optimizer, device, batch_size=128, num_epochs=100) mlp_train_data_loader = torch.utils.data.DataLoader(mlp_train_data, batch_size=128, shuffle=True) loss = mlp_model.fit(mlp_train_data_loader) From dc4d12e4b92fb30ee72168d9e8b2aaffe7fa488f Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 22 Feb 2023 15:48:46 +0800 Subject: [PATCH 140/601] Delete equation_generator.py --- datasets/hed/equation_generator.py | 266 ----------------------------- 1 file changed, 266 deletions(-) delete mode 100644 datasets/hed/equation_generator.py diff --git a/datasets/hed/equation_generator.py b/datasets/hed/equation_generator.py deleted file mode 100644 index 3cf735b..0000000 --- a/datasets/hed/equation_generator.py +++ /dev/null @@ -1,266 +0,0 @@ -import os -import itertools -import random -import numpy as np -from PIL import Image -import pickle - - -def get_sign_path_list(data_dir, sign_names): - sign_num = len(sign_names) - index_dict = dict(zip(sign_names, list(range(sign_num)))) - ret = [[] for _ in range(sign_num)] - for path in os.listdir(data_dir): - if path in sign_names: - index = index_dict[path] - sign_path = os.path.join(data_dir, path) - for p in os.listdir(sign_path): - ret[index].append(os.path.join(sign_path, p)) - return ret - - -def split_pool_by_rate(pools, rate, seed=None): - if seed is not None: - random.seed(seed) - ret1 = [] - ret2 = [] - for pool in pools: - random.shuffle(pool) - num = int(len(pool) * rate) - ret1.append(pool[:num]) - ret2.append(pool[num:]) - return ret1, ret2 - - -def int_to_system_form(num, system_num): - if num is 0: - return "0" - ret = "" - while num > 0: - ret += str(num % system_num) - num //= system_num - return ret[::-1] - - -def generator_equations( - left_opt_len, right_opt_len, res_opt_len, system_num, label, generate_type -): - expr_len = left_opt_len + right_opt_len - num_list = "".join([str(i) for i in range(system_num)]) - ret = [] - if generate_type == "all": - candidates = itertools.product(num_list, repeat=expr_len) - else: - candidates = ["".join(random.sample(["0", "1"] * expr_len, expr_len))] - random.shuffle(candidates) - for nums in candidates: - left_num = "".join(nums[:left_opt_len]) - right_num = "".join(nums[left_opt_len:]) - left_value = int(left_num, system_num) - right_value = int(right_num, system_num) - result_value = left_value + right_value - if label == "negative": - result_value += random.randint(-result_value, result_value) - if left_value + right_value == result_value: - continue - result_num = int_to_system_form(result_value, system_num) - # leading zeros - if res_opt_len != len(result_num): - continue - if (left_opt_len > 1 and left_num[0] == "0") or ( - right_opt_len > 1 and right_num[0] == "0" - ): - continue - - # add leading zeros - if res_opt_len < len(result_num): - continue - while len(result_num) < res_opt_len: - result_num = "0" + result_num - # continue - ret.append( - left_num + "+" + right_num + "=" + result_num - ) # current only consider '+' and '=' - # print(ret[-1]) - return ret - - -def generator_equation_by_len(equation_len, system_num=2, label=0, require_num=1): - generate_type = "one" - ret = [] - equation_sign_num = 2 # '+' and '=' - while len(ret) < require_num: - left_opt_len = random.randint(1, equation_len - 1 - equation_sign_num) - right_opt_len = random.randint( - 1, equation_len - left_opt_len - equation_sign_num - ) - res_opt_len = equation_len - left_opt_len - right_opt_len - equation_sign_num - ret.extend( - generator_equations( - left_opt_len, - right_opt_len, - res_opt_len, - system_num, - label, - generate_type, - ) - ) - return ret - - -def generator_equations_by_len( - equation_len, system_num=2, label=0, repeat_times=1, keep=1, generate_type="all" -): - ret = [] - equation_sign_num = 2 # '+' and '=' - for left_opt_len in range(1, equation_len - (2 + equation_sign_num) + 1): - for right_opt_len in range( - 1, equation_len - left_opt_len - (1 + equation_sign_num) + 1 - ): - res_opt_len = ( - equation_len - left_opt_len - right_opt_len - equation_sign_num - ) - for i in range(repeat_times): # generate more equations - if random.random() > keep ** (equation_len): - continue - ret.extend( - generator_equations( - left_opt_len, - right_opt_len, - res_opt_len, - system_num, - label, - generate_type, - ) - ) - return ret - - -def generator_equations_by_max_len( - max_equation_len, - system_num=2, - label=0, - repeat_times=1, - keep=1, - generate_type="all", - num_per_len=None, -): - ret = [] - equation_sign_num = 2 # '+' and '=' - for equation_len in range(3 + equation_sign_num, max_equation_len + 1): - if num_per_len is None: - ret.extend( - generator_equations_by_len( - equation_len, system_num, label, repeat_times, keep, generate_type - ) - ) - else: - ret.extend( - generator_equation_by_len( - equation_len, system_num, label, require_num=num_per_len - ) - ) - return ret - - -def generator_equation_images(image_pools, equations, signs, shape, seed, is_color): - if seed is not None: - random.seed(seed) - ret = [] - sign_num = len(signs) - sign_index_dict = dict(zip(signs, list(range(sign_num)))) - for equation in equations: - data = [] - for sign in equation: - index = sign_index_dict[sign] - pick = random.randint(0, len(image_pools[index]) - 1) - if is_color: - image = ( - Image.open(image_pools[index][pick]).convert("RGB").resize(shape) - ) - else: - image = Image.open(image_pools[index][pick]).convert("I").resize(shape) - image_array = np.array(image) - image_array = (image_array - 127) * (1.0 / 128) - data.append(image_array) - ret.append(np.array(data)) - return ret - - -def get_equation_std_data( - data_dir, - sign_dir_lists, - sign_output_lists, - shape=(28, 28), - train_max_equation_len=10, - test_max_equation_len=10, - system_num=2, - tmp_file_prev=None, - seed=None, - train_num_per_len=10, - test_num_per_len=10, - is_color=False, -): - tmp_file = "" - if tmp_file_prev is not None: - tmp_file = "%s_train_len_%d_test_len_%d_sys_%d_.pk" % ( - tmp_file_prev, - train_max_equation_len, - test_max_equation_len, - system_num, - ) - if os.path.exists(tmp_file): - return pickle.load(open(tmp_file, "rb")) - - image_pools = get_sign_path_list(data_dir, sign_dir_lists) - train_pool, test_pool = split_pool_by_rate(image_pools, 0.8, seed) - - ret = {} - for label in ["positive", "negative"]: - print("Generating equations.") - train_equations = generator_equations_by_max_len( - train_max_equation_len, system_num, label, num_per_len=train_num_per_len - ) - test_equations = generator_equations_by_max_len( - test_max_equation_len, system_num, label, num_per_len=test_num_per_len - ) - print(train_equations) - print(test_equations) - print("Generated equations.") - print("Generating equation image data.") - ret["train:%s" % (label)] = generator_equation_images( - train_pool, train_equations, sign_output_lists, shape, seed, is_color - ) - ret["test:%s" % (label)] = generator_equation_images( - test_pool, test_equations, sign_output_lists, shape, seed, is_color - ) - print("Generated equation image data.") - - if tmp_file_prev is not None: - pickle.dump(ret, open(tmp_file, "wb")) - return ret - - -if __name__ == "__main__": - data_dirs = [ - "./dataset/mnist_images", - "./dataset/random_images", - ] # , "../dataset/cifar10_images"] - tmp_file_prevs = [ - "mnist_equation_data", - "random_equation_data", - ] # , "cifar10_equation_data"] - for data_dir, tmp_file_prev in zip(data_dirs, tmp_file_prevs): - data = get_equation_std_data( - data_dir=data_dir, - sign_dir_lists=["0", "1", "10", "11"], - sign_output_lists=["0", "1", "+", "="], - shape=(28, 28), - train_max_equation_len=26, - test_max_equation_len=26, - system_num=2, - tmp_file_prev=tmp_file_prev, - train_num_per_len=300, - test_num_per_len=300, - is_color=False, - ) From 4d7b6570cbb3e804da69f4d5045d6aca11e9c56b Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 22 Feb 2023 15:49:13 +0800 Subject: [PATCH 141/601] Create README.md --- datasets/hed/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 datasets/hed/README.md diff --git a/datasets/hed/README.md b/datasets/hed/README.md new file mode 100644 index 0000000..1044f38 --- /dev/null +++ b/datasets/hed/README.md @@ -0,0 +1 @@ +Download the Handwritten Equation Decipherment dataset from [NJU Box](https://box.nju.edu.cn/d/23cd88c9325b4d96a571/) to this folder From b87793bf3adae9c1edf473759d5a893b13be18c3 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 22 Feb 2023 16:50:24 +0800 Subject: [PATCH 142/601] Update README.md --- datasets/hed/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/datasets/hed/README.md b/datasets/hed/README.md index 1044f38..f48c97d 100644 --- a/datasets/hed/README.md +++ b/datasets/hed/README.md @@ -1 +1,4 @@ -Download the Handwritten Equation Decipherment dataset from [NJU Box](https://box.nju.edu.cn/d/23cd88c9325b4d96a571/) to this folder +Download the Handwritten Equation Decipherment dataset from [NJU Box](https://box.nju.edu.cn/f/391c2d48c32b436cb833/) to this folder and unzip it: +``` +unzip HED.zip +``` From 7fbe96fa79c1aef602edb5b167fdaa19c659e5d3 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 22 Feb 2023 17:39:53 +0800 Subject: [PATCH 143/601] Update get_hed.py --- datasets/hed/get_hed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datasets/hed/get_hed.py b/datasets/hed/get_hed.py index 8b61b62..b317d94 100644 --- a/datasets/hed/get_hed.py +++ b/datasets/hed/get_hed.py @@ -41,7 +41,7 @@ def get_pretrain_data(labels, image_size=(28, 28, 1)): X = [] for label in labels: label_path = os.path.join( - "./datasets/hed/dataset/mnist_images", label + "./datasets/hed/mnist_images", label ) img_path_list = os.listdir(label_path) for img_path in img_path_list: From 28149e36c5b1ca4415d0a82c0439bf2efe97c304 Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Wed, 22 Feb 2023 18:53:40 +0800 Subject: [PATCH 144/601] add 'weights' folder --- weights/all_weights_here.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 weights/all_weights_here.txt diff --git a/weights/all_weights_here.txt b/weights/all_weights_here.txt new file mode 100644 index 0000000..e69de29 From 7a424c8eac0c0c2d9d63cc2b9ec713d1c280231d Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 24 Feb 2023 17:03:51 +0800 Subject: [PATCH 145/601] Update framework_hed.py --- framework_hed.py | 176 ++++++++++++++++------------------------------- 1 file changed, 59 insertions(+), 117 deletions(-) diff --git a/framework_hed.py b/framework_hed.py index 3476462..b7439c3 100644 --- a/framework_hed.py +++ b/framework_hed.py @@ -119,7 +119,7 @@ def hed_pretrain(kb, cls, recorder): cls.load_state_dict(torch.load("./weights/pretrain_weights.pth")) -def get_char_acc(model, X, consistent_pred_res, mapping): +def _get_char_acc(model, X, consistent_pred_res, mapping): original_pred_res = model.predict(X)['cls'] pred_res = flatten(mapping_res(original_pred_res, mapping)) INFO('Current model\'s output: ', pred_res) @@ -177,22 +177,29 @@ def abduce_and_train(model, abducer, mapping, train_X_true, select_num): model.train([X[idx] for idx in consistent_idx], remapping_res(consistent_pred_res, mapping)) consistent_acc = len(consistent_idx) / select_num - char_acc = get_char_acc(model, [X[idx] for idx in consistent_idx], consistent_pred_res, mapping) + char_acc = _get_char_acc(model, [X[idx] for idx in consistent_idx], consistent_pred_res, mapping) INFO('consistent_acc is %s, char_acc is %s' % (consistent_acc, char_acc)) return consistent_acc, char_acc, mapping +def _remove_duplicate_rule(rule_dict): + add_nums_dict = {} + for r in list(rule_dict): + add_nums = str(r.split(']')[0].split('[')[1]) + str(r.split(']')[1].split('[')[1]) # r = 'my_op([1], [0], [1, 0])' then add_nums = '10' + if add_nums in add_nums_dict: + old_r = add_nums_dict[add_nums] + if rule_dict[r] >= rule_dict[old_r]: + rule_dict.pop(old_r) + add_nums_dict[add_nums] = r + else: + rule_dict.pop(r) + else: + add_nums_dict[add_nums] = r + return list(rule_dict) -def output_rules(rules): - all_rule_dict = {} - for rule in rules: - for r in rule: - all_rule_dict[r] = 1 if r not in all_rule_dict else all_rule_dict[r] + 1 - rule_dict = {rule: cnt for rule, cnt in all_rule_dict.items()}# if cnt >= 5} - return rule_dict -def get_rules_from_data(model, abducer, mapping, train_X_true, samples_per_rule, logic_output_dim): +def get_rules_from_data(model, abducer, mapping, train_X_true, samples_per_rule, samples_num): rules = [] - for _ in range(logic_output_dim): + for _ in range(samples_num): while True: select_idx = np.random.randint(len(train_X_true), size=samples_per_rule) X = [] @@ -213,83 +220,32 @@ def get_rules_from_data(model, abducer, mapping, train_X_true, samples_per_rule, if rule != None: break rules.append(rule) - return rules - - -def get_mlp_vector(model, abducer, mapping, X, rules): - original_pred_res = model.predict([X])['cls'] - pred_res = flatten(mapping_res(original_pred_res, mapping)) - vector = [] - for rule in rules: - if abducer.kb.consist_rule(pred_res, rule): - vector.append(1) - else: - vector.append(0) - return vector - - -def get_mlp_data(model, abducer, mapping, X_true, X_false, rules): - mlp_vectors = [] - mlp_labels = [] - for X in X_true: - mlp_vectors.append(get_mlp_vector(model, abducer, mapping, X, rules)) - mlp_labels.append(1) - for X in X_false: - mlp_vectors.append(get_mlp_vector(model, abducer, mapping, X, rules)) - mlp_labels.append(0) - return np.array(mlp_vectors, dtype=np.float32), np.array(mlp_labels, dtype=np.int64) - -def get_all_mlp_data(model, abducer, mapping, X_true, X_false, rules, min_len, max_len): - for equation_len in range(min_len, max_len + 1): - mlp_vectors, mlp_labels = get_mlp_data(model, abducer, mapping, X_true[equation_len], X_false[equation_len], rules) - if equation_len == min_len: - all_mlp_vectors = mlp_vectors - all_mlp_labels = mlp_labels - else: - all_mlp_vectors = np.concatenate((all_mlp_vectors, mlp_vectors)) - all_mlp_labels = np.concatenate((all_mlp_labels, mlp_labels)) - return all_mlp_vectors, all_mlp_labels - - -def validation(model, abducer, mapping, logic_output_dim, rules, train_X_true, train_X_false, val_X_true, val_X_false): - mlp_train_vectors, mlp_train_labels = get_mlp_data(model, abducer, mapping, train_X_true, train_X_false, rules) - mlp_train_data = BasicDataset(mlp_train_vectors, mlp_train_labels) - mlp_val_vectors, mlp_val_labels = get_mlp_data(model, abducer, mapping, val_X_true, val_X_false, rules) - mlp_val_data = BasicDataset(mlp_val_vectors, mlp_val_labels) + all_rule_dict = {} + for rule in rules: + for r in rule: + all_rule_dict[r] = 1 if r not in all_rule_dict else all_rule_dict[r] + 1 + rule_dict = {rule: cnt for rule, cnt in all_rule_dict.items() if cnt >= 5} + rules = _remove_duplicate_rule(rule_dict) - best_accuracy = 0 - # Try three times to find the best mlp - for _ in range(3): - INFO("Training mlp...") - mlp = MLP(input_dim=logic_output_dim) - criterion = nn.CrossEntropyLoss() - optimizer = torch.optim.Adam(mlp.parameters(), lr=0.01, betas=(0.9, 0.999)) - device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - - mlp_model = BasicModel(mlp, criterion, optimizer, device, batch_size=128, num_epochs=100) - mlp_train_data_loader = torch.utils.data.DataLoader(mlp_train_data, batch_size=128, shuffle=True) - - loss = mlp_model.fit(mlp_train_data_loader) - INFO("mlp training final loss is %f" % loss) - - mlp_val_data_loader = torch.utils.data.DataLoader(mlp_val_data, batch_size=64, shuffle=True) - accuracy = mlp_model.val(mlp_val_data_loader) - - if accuracy > best_accuracy: - best_accuracy = accuracy - return best_accuracy - - + return rules +def _get_consist_rule_acc(model, abducer, mapping, rules, X): + cnt = 0 + for x in X: + original_pred_res = model.predict([x])['cls'] + pred_res = flatten(mapping_res(original_pred_res, mapping)) + if abducer.kb.consist_rule(pred_res, rules): + cnt += 1 + return cnt / len(X) def train_with_rule(model, abducer, train_data, val_data, select_num=10, min_len=5, max_len=8): train_X = train_data val_X = val_data - logic_output_dim = 50 + samples_num = 50 samples_per_rule = 3 # Start training / for each length of equations @@ -324,12 +280,15 @@ def train_with_rule(model, abducer, train_data, val_data, select_num=10, min_len # The condition has been satisfied continuously five times if condition_cnt >= 5: INFO("Now checking if we can go to next course") - rules = get_rules_from_data(model, abducer, mapping, train_X_true, samples_per_rule, logic_output_dim) - INFO('Learned rules from data:', output_rules(rules)) - best_accuracy = validation(model, abducer, mapping, logic_output_dim, rules, train_X_true, train_X_false, val_X_true, val_X_false) - INFO('best_accuracy is %f\n' %(best_accuracy)) + rules = get_rules_from_data(model, abducer, mapping, train_X_true, samples_per_rule, samples_num) + INFO('Learned rules from data:', rules) + + true_consist_rule_acc = _get_consist_rule_acc(model, abducer, mapping, rules, val_X_true) + false_consist_rule_acc = _get_consist_rule_acc(model, abducer, mapping, rules, val_X_false) + + INFO('consist_rule_acc is %f, %f\n' %(true_consist_rule_acc, false_consist_rule_acc)) # decide next course or restart - if best_accuracy > 0.88: + if true_consist_rule_acc > 0.9 and false_consist_rule_acc < 0.1: torch.save(model.cls_list[0].model.state_dict(), "./weights/weights_%d.pth" % equation_len) break else: @@ -347,50 +306,33 @@ def hed_test(model, abducer, mapping, train_data, test_data, min_len=5, max_len= test_X = test_data # Calcualte how many equations should be selected in each length - # for each length, there are select_equation_cnt[equation_len] rules + # for each length, there are equation_samples_num[equation_len] rules print("Now begin to train final mlp model") - select_equation_cnt = [] + equation_samples_num = [] len_cnt = max_len - min_len + 1 - logic_output_dim = 50 - select_equation_cnt += [0] * min_len - if logic_output_dim % len_cnt == 0: - select_equation_cnt += [logic_output_dim // len_cnt] * len_cnt + samples_num = 50 + equation_samples_num += [0] * min_len + if samples_num % len_cnt == 0: + equation_samples_num += [samples_num // len_cnt] * len_cnt else: - select_equation_cnt += [logic_output_dim // len_cnt] * len_cnt - select_equation_cnt[-1] += logic_output_dim % len_cnt - assert sum(select_equation_cnt) == logic_output_dim + equation_samples_num += [samples_num // len_cnt] * len_cnt + equation_samples_num[-1] += samples_num % len_cnt + assert sum(equation_samples_num) == samples_num # Abduce rules rules = [] samples_per_rule = 3 for equation_len in range(min_len, max_len + 1): - equation_rules = get_rules_from_data(model, abducer, mapping, train_X[1][equation_len], samples_per_rule, select_equation_cnt[equation_len]) + equation_rules = get_rules_from_data(model, abducer, mapping, train_X[1][equation_len], samples_per_rule, equation_samples_num[equation_len]) rules.extend(equation_rules) - INFO('Learned rules from data:', output_rules(rules)) - - mlp_train_vectors, mlp_train_labels = get_all_mlp_data(model, abducer, mapping, train_X[1], train_X[0], rules, min_len, max_len) - mlp_train_data = BasicDataset(mlp_train_vectors, mlp_train_labels) - - # Try three times to find the best mlp - for _ in range(3): - mlp = MLP(input_dim=logic_output_dim) - criterion = nn.CrossEntropyLoss() - optimizer = torch.optim.Adam(mlp.parameters(), lr=0.01, betas=(0.9, 0.999)) - device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - - mlp_model = BasicModel(mlp, criterion, optimizer, device, batch_size=128, num_epochs=100) - mlp_train_data_loader = torch.utils.data.DataLoader(mlp_train_data, batch_size=128, shuffle=True) - - loss = mlp_model.fit(mlp_train_data_loader) - INFO("mlp training final loss is %f" % loss) + rules = list(set(rules)) + INFO('Learned rules from data:', rules) + - for equation_len in range(5, 27): - mlp_test_vectors, mlp_test_labels = get_mlp_data(model, abducer, mapping, test_X[1][equation_len], test_X[0][equation_len], rules) - mlp_test_data = BasicDataset(mlp_test_vectors, mlp_test_labels) - mlp_test_data_loader = torch.utils.data.DataLoader(mlp_test_data, batch_size=64, shuffle=True) - accuracy = mlp_model.val(mlp_test_data_loader) - INFO("The accuracy of testing length %d equations is: %f" % (equation_len, accuracy)) - INFO("\n") + for equation_len in range(5, 27): + true_consist_rule_acc = _get_consist_rule_acc(model, abducer, mapping, rules, test_X[1][equation_len]) + false_consist_rule_acc = _get_consist_rule_acc(model, abducer, mapping, rules, test_X[0][equation_len]) + INFO('consist_rule_acc of testing length %d equations are %f, %f' %(equation_len, true_consist_rule_acc, false_consist_rule_acc)) if __name__ == "__main__": pass From 7dc2ce032aa1006967ee62b2aaf445d0edc39cdb Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Wed, 1 Mar 2023 16:48:46 +0800 Subject: [PATCH 146/601] update TODO in kb.py --- abducer/kb.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 959b4ac..6d467ea 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -48,15 +48,19 @@ class KBBase(ABC): address_idx_list = list(combinations(list(range(len(flatten(pred_res)))), address_num)) for address_idx in address_idx_list: + # TODO: è¦ä¹ˆaddress_by_idx放这个类,è¦ä¹ˆå®šä¹‰abstractmethod candidates = self.address_by_idx(pred_res, key, address_idx, multiple_predictions) new_candidates += candidates return new_candidates - def abduction(self, pred_res, key, max_address_num, require_more_address, multiple_predictions=False): + def abduction(self, pred_res, key, max_address_num, require_more_address=0, multiple_predictions=False): candidates = [] + # TODO: 这里的len(pred_res)考虑了multiple_predictionså—? for address_num in range(len(pred_res) + 1): if address_num == 0: + # TODO: 䏿˜¯æ‰€æœ‰çš„key都是数字,也å¯ä»¥æ˜¯å­—符串,甚至列表? + # TODO: check type (str int float multiple_pred ...) if abs(self.logic_forward(pred_res) - key) <= 1e-3: candidates.append(pred_res) else: @@ -88,7 +92,8 @@ class ClsKB(KBBase): self.GKB_flag = GKB_flag self.pseudo_label_list = pseudo_label_list self.len_list = len_list - self.prolog_flag = False + self.prolog_flag = False # TODO:没用? + # TODO: 既然pseudo_label_list len_list prolog_flag都存为self了,那为啥åˆä¼ åˆ°åŽé¢çš„æ–¹æ³•里,或者说self就没用上 if GKB_flag: self.base = {} @@ -143,6 +148,7 @@ class ClsKB(KBBase): def logic_forward(self): pass + # TODO: abductionå’Œabduce_candidates命å上太相近了,å³ä½¿è¿™æ ·ï¼Œä¹Ÿæœ‰å…¶ä¸­ä¸€ä¸ªæ˜¯ç§æœ‰æ–¹æ³•加"_"å§ def abduce_candidates(self, pred_res, key, max_address_num=-1, require_more_address=0, multiple_predictions=False): if self.GKB_flag: return self.abduce_from_GKB(pred_res, key, max_address_num, require_more_address) From ed60061451bf14c3ffabd4b4d9a5e38208677929 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 1 Mar 2023 18:34:26 +0800 Subject: [PATCH 147/601] Update kb.py --- abducer/kb.py | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index 6d467ea..b78ab64 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -21,7 +21,7 @@ sys.path.append("..") from collections import defaultdict from itertools import product, combinations -from utils.utils import flatten, reform_idx, hamming_dist +from utils.utils import flatten, reform_idx, hamming_dist, check_is_equal from multiprocessing import Pool @@ -39,8 +39,12 @@ class KBBase(ABC): @abstractmethod def abduce_candidates(self): pass + + @abstractmethod + def address_by_idx(self): + pass - def address(self, address_num, pred_res, key, multiple_predictions=False): + def _address(self, address_num, pred_res, key, multiple_predictions=False): new_candidates = [] if not multiple_predictions: address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) @@ -48,23 +52,19 @@ class KBBase(ABC): address_idx_list = list(combinations(list(range(len(flatten(pred_res)))), address_num)) for address_idx in address_idx_list: - # TODO: è¦ä¹ˆaddress_by_idx放这个类,è¦ä¹ˆå®šä¹‰abstractmethod candidates = self.address_by_idx(pred_res, key, address_idx, multiple_predictions) new_candidates += candidates return new_candidates - def abduction(self, pred_res, key, max_address_num, require_more_address=0, multiple_predictions=False): + def _abduce_by_abduction(self, pred_res, key, max_address_num, require_more_address=0, multiple_predictions=False): candidates = [] - # TODO: 这里的len(pred_res)考虑了multiple_predictionså—? - for address_num in range(len(pred_res) + 1): + for address_num in range(len(flatten(pred_res)) + 1): if address_num == 0: - # TODO: 䏿˜¯æ‰€æœ‰çš„key都是数字,也å¯ä»¥æ˜¯å­—符串,甚至列表? - # TODO: check type (str int float multiple_pred ...) - if abs(self.logic_forward(pred_res) - key) <= 1e-3: + if check_is_equal(pred_res, key): candidates.append(pred_res) else: - new_candidates = self.address(address_num, pred_res, key, multiple_predictions) + new_candidates = self._address(address_num, pred_res, key, multiple_predictions) candidates += new_candidates if len(candidates) > 0: @@ -77,7 +77,7 @@ class KBBase(ABC): for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): if address_num > max_address_num: return candidates, min_address_num, address_num - 1 - new_candidates = self.address(address_num, pred_res, key, multiple_predictions) + new_candidates = self._address(address_num, pred_res, key, multiple_predictions) candidates += new_candidates return candidates, min_address_num, address_num @@ -92,12 +92,10 @@ class ClsKB(KBBase): self.GKB_flag = GKB_flag self.pseudo_label_list = pseudo_label_list self.len_list = len_list - self.prolog_flag = False # TODO:没用? - # TODO: 既然pseudo_label_list len_list prolog_flag都存为self了,那为啥åˆä¼ åˆ°åŽé¢çš„æ–¹æ³•里,或者说self就没用上 if GKB_flag: self.base = {} - X, Y = self._get_GKB(self.pseudo_label_list, self.len_list) + X, Y = self._get_GKB() for x, y in zip(X, Y): self.base.setdefault(len(x), defaultdict(list))[y].append(x) else: @@ -117,10 +115,10 @@ class ClsKB(KBBase): return XY_list # Parallel get GKB - def _get_GKB(self, pseudo_label_list, len_list): + def _get_GKB(self): # all_X = [] # for length in len_list: - # all_X += list(product(pseudo_label_list, repeat = length)) + # all_X += list(product(self.pseudo_label_list, repeat = length)) # X, Y = [], [] # for x in all_X: @@ -130,10 +128,10 @@ class ClsKB(KBBase): # Y.append(y) X, Y = [], [] - for length in len_list: + for length in self.len_list: arg_list = [] - for pre_x in pseudo_label_list: - post_x_it = product(pseudo_label_list, repeat=length - 1) + for pre_x in self.pseudo_label_list: + post_x_it = product(self.pseudo_label_list, repeat=length - 1) arg_list.append((pre_x, post_x_it)) with Pool(processes=len(arg_list)) as pool: ret_list = pool.map(self._get_XY_list, arg_list) @@ -148,14 +146,13 @@ class ClsKB(KBBase): def logic_forward(self): pass - # TODO: abductionå’Œabduce_candidates命å上太相近了,å³ä½¿è¿™æ ·ï¼Œä¹Ÿæœ‰å…¶ä¸­ä¸€ä¸ªæ˜¯ç§æœ‰æ–¹æ³•加"_"å§ def abduce_candidates(self, pred_res, key, max_address_num=-1, require_more_address=0, multiple_predictions=False): if self.GKB_flag: - return self.abduce_from_GKB(pred_res, key, max_address_num, require_more_address) + return self._abduce_from_GKB(pred_res, key, max_address_num, require_more_address) else: - return self.abduction(pred_res, key, max_address_num, require_more_address, multiple_predictions) + return self._abduce_by_abduction(pred_res, key, max_address_num, require_more_address, multiple_predictions) - def abduce_from_GKB(self, pred_res, key, max_address_num, require_more_address): + def _abduce_from_GKB(self, pred_res, key, max_address_num, require_more_address): if self.base == {} or len(pred_res) not in self.len_list: return [] @@ -263,7 +260,7 @@ class prolog_KB(KBBase): pass def abduce_candidates(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): - return self.abduction(pred_res, key, max_address_num, require_more_address, multiple_predictions) + return self._abduce_by_abduction(pred_res, key, max_address_num, require_more_address, multiple_predictions) def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): candidates = [] From b08a58aab7c0600acf2f175e004ae9d3b250d90d Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 2 Mar 2023 09:24:06 +0800 Subject: [PATCH 148/601] Add check_equal --- utils/utils.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/utils/utils.py b/utils/utils.py index f4db6f2..1138361 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -72,3 +72,18 @@ def remapping_res(pred_res, m): for key, value in m.items(): remapping[value] = key return [[remapping[symbol] for symbol in formula] for formula in pred_res] + +def check_equal(a, b): + if isinstance(a, (int, float)) and isinstance(b, (int, float)): + return abs(a - b) <= 1e-3 + + if isinstance(a, list) and isinstance(b, list): + if len(a) != len(b): + return False + for i in range(len(a)): + if not check_equal(a[i], b[i]): + return False + return True + + else: + return a == b From 650c172d61e4b9ef6c468ae07e2826086c6f3dec Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Thu, 2 Mar 2023 09:24:41 +0800 Subject: [PATCH 149/601] Update kb.py --- abducer/kb.py | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index b78ab64..b9beb3f 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -21,7 +21,7 @@ sys.path.append("..") from collections import defaultdict from itertools import product, combinations -from utils.utils import flatten, reform_idx, hamming_dist, check_is_equal +from utils.utils import flatten, reform_idx, hamming_dist, check_equal from multiprocessing import Pool @@ -56,12 +56,12 @@ class KBBase(ABC): new_candidates += candidates return new_candidates - def _abduce_by_abduction(self, pred_res, key, max_address_num, require_more_address=0, multiple_predictions=False): + def _abduce_by_search(self, pred_res, key, max_address_num, require_more_address=0, multiple_predictions=False): candidates = [] for address_num in range(len(flatten(pred_res)) + 1): if address_num == 0: - if check_is_equal(pred_res, key): + if check_equal(self.logic_forward(pred_res), key): candidates.append(pred_res) else: new_candidates = self._address(address_num, pred_res, key, multiple_predictions) @@ -114,19 +114,8 @@ class ClsKB(KBBase): XY_list.append((x, y)) return XY_list - # Parallel get GKB + # Parallel _get_GKB def _get_GKB(self): - # all_X = [] - # for length in len_list: - # all_X += list(product(self.pseudo_label_list, repeat = length)) - - # X, Y = [], [] - # for x in all_X: - # y = self.logic_forward(x) - # if y != np.inf: - # X.append(x) - # Y.append(y) - X, Y = [], [] for length in self.len_list: arg_list = [] @@ -148,11 +137,11 @@ class ClsKB(KBBase): def abduce_candidates(self, pred_res, key, max_address_num=-1, require_more_address=0, multiple_predictions=False): if self.GKB_flag: - return self._abduce_from_GKB(pred_res, key, max_address_num, require_more_address) + return self._abduce_by_GKB(pred_res, key, max_address_num, require_more_address) else: - return self._abduce_by_abduction(pred_res, key, max_address_num, require_more_address, multiple_predictions) + return self._abduce_by_search(pred_res, key, max_address_num, require_more_address, multiple_predictions) - def _abduce_from_GKB(self, pred_res, key, max_address_num, require_more_address): + def _abduce_by_GKB(self, pred_res, key, max_address_num, require_more_address): if self.base == {} or len(pred_res) not in self.len_list: return [] @@ -260,7 +249,7 @@ class prolog_KB(KBBase): pass def abduce_candidates(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): - return self._abduce_by_abduction(pred_res, key, max_address_num, require_more_address, multiple_predictions) + return self._abduce_by_search(pred_res, key, max_address_num, require_more_address, multiple_predictions) def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): candidates = [] From fcda456cb60328b97f45afe00d928cb80cc13090 Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Thu, 2 Mar 2023 15:05:37 +0800 Subject: [PATCH 150/601] update TODO in kb.py --- abducer/kb.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/abducer/kb.py b/abducer/kb.py index b9beb3f..bbd6c93 100644 --- a/abducer/kb.py +++ b/abducer/kb.py @@ -137,6 +137,7 @@ class ClsKB(KBBase): def abduce_candidates(self, pred_res, key, max_address_num=-1, require_more_address=0, multiple_predictions=False): if self.GKB_flag: + # TODO: 这里有å¯èƒ½æ˜¯multiple_predictionså— return self._abduce_by_GKB(pred_res, key, max_address_num, require_more_address) else: return self._abduce_by_search(pred_res, key, max_address_num, require_more_address, multiple_predictions) @@ -200,7 +201,7 @@ class add_KB(ClsKB): def logic_forward(self, nums): return sum(nums) - +# TODO:这是个回归任务(对于y而言),在logic_forward加roundå˜æˆç¦»æ•£çš„分类任务固然å¯è¡Œï¼Œä½†æœ€å¥½è¿˜æ˜¯ç”¨RegKBå§ï¼Œä½œä¸ºä¾‹å­ç¤ºèŒƒã€‚还需è¦å¯¹ä¸‹é¢çš„ClsKB进行修改(è§TODO) class HWF_KB(ClsKB): def __init__( self, GKB_flag=False, pseudo_label_list=['1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', 'times', 'div'], len_list=[1, 3, 5, 7] @@ -334,7 +335,13 @@ class HED_prolog_KB(prolog_KB): # def consist_rules(self, pred_res, rules): - +# TODO:这里需è¦ä¿®æ”¹ä¸€ä¸‹è¿™ä¸ªç±»ï¼ŒåŽŸæœ¬çš„RegKB是对GKB而言的,现在需è¦å’ŒClsKBä¸€æ ·åŒæ—¶æ”¯æŒGKBå’ŒéžGKB。需è¦è¡¥å……éžGKB部分(å¯èƒ½ç»§æ‰¿_abduce_by_search就行),以åŠä¿®æ”¹GKB部分_abduce_by_GKB的逻辑(原本逻辑是找与key最近的yçš„abduce结果,现在改æˆä¸Žkey在一定误差范围内的yçš„abduce结果) +# TODO:我ç†è§£çš„RegKB是这样的: +# TODO:1. 对GKB而言,å³_abduce_by_GKB,给定keyå’Œlength,还需è¦ä¸€ä¸ªself.max_err,返回所有与keyç»å¯¹å€¼å°äºŽmax_errçš„abduction结果 +# TODO:比如GKB里的y有[1.3, 1.49, 1.50, 1.52, 1.6],若key=1.5,max_err=1e-5,则返回[y=1.50]çš„abduction结果;若key=1.5,max_err=0.05,则返回所有[y=1.49, 1.50, 1.52]çš„abduction结果 +# TODO:因此在二分查找bisect_leftåŽï¼Œéœ€è¦åˆ†åˆ«å¾€å‰å’Œå¾€åŽé历,从GKB里找符åˆè¯¯å·®çš„y +# TODO:self.max_err默认值å–很å°å°±è¡Œï¼Œæ¯”如HWF这类任务;但有些任务(比如法院刑期预测)的max_err需è¦å¤§äº›ï¼Œå› æ­¤å¯ä»¥ç”±ç”¨æˆ·è‡ªå®šä¹‰ +# TODO:2. 对éžGKB而言,估计直接用_abduce_by_search就行,check_equalé‚£é™å®šä¸ºæ•°å­—且控制回归误差max_err class RegKB(KBBase): def __init__(self, GKB_flag=False, X=None, Y=None): super().__init__() @@ -355,7 +362,7 @@ class RegKB(KBBase): def logic_forward(self): pass - def abduce_candidates(self, key, length=None): + def _abduce_by_GKB(self, key, length=None): if key is None: return self.get_all_candidates() From 37c1c446d9e3c25146c8d08db5db64b0b22ff213 Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Fri, 3 Mar 2023 14:00:51 +0800 Subject: [PATCH 151/601] update package structure --- weights/all_weights_here.txt => abl/__init__.py | 0 abl/abducer/__init__.py | 0 {abducer => abl/abducer}/abducer_base.py | 11 ++++++----- {abducer => abl/abducer}/kb.py | 4 ++-- framework.py => abl/framework.py | 2 +- framework_hed.py => abl/framework_hed.py | 13 ++++++++----- abl/models/__init__.py | 0 {models => abl/models}/basic_model.py | 0 {models => abl/models}/lenet5.py | 0 {models => abl/models}/nn.py | 5 ----- {models => abl/models}/wabl_models.py | 1 - {utils => abl/utils}/plog.py | 0 {utils => abl/utils}/utils.py | 2 +- {datasets => examples/datasets}/data_generator.py | 0 {datasets => examples/datasets}/hed/BK.pl | 0 {datasets => examples/datasets}/hed/README.md | 0 {datasets => examples/datasets}/hed/get_hed.py | 0 {datasets => examples/datasets}/hed/learn_add.pl | 0 {datasets => examples/datasets}/hwf/README.md | 0 {datasets => examples/datasets}/hwf/get_hwf.py | 0 .../datasets}/mnist_add/get_mnist_add.py | 0 .../datasets}/mnist_add/test_data.txt | 0 .../datasets}/mnist_add/train_data.txt | 0 example.py => examples/example.py | 0 nonshare_example.py => examples/nonshare_example.py | 0 share_example.py => examples/share_example.py | 0 examples/weights/all_weights_here.txt | 0 27 files changed, 18 insertions(+), 20 deletions(-) rename weights/all_weights_here.txt => abl/__init__.py (100%) create mode 100644 abl/abducer/__init__.py rename {abducer => abl/abducer}/abducer_base.py (98%) rename {abducer => abl/abducer}/kb.py (99%) rename framework.py => abl/framework.py (98%) rename framework_hed.py => abl/framework_hed.py (97%) create mode 100644 abl/models/__init__.py rename {models => abl/models}/basic_model.py (100%) rename {models => abl/models}/lenet5.py (100%) rename {models => abl/models}/nn.py (97%) rename {models => abl/models}/wabl_models.py (99%) rename {utils => abl/utils}/plog.py (100%) rename {utils => abl/utils}/utils.py (98%) rename {datasets => examples/datasets}/data_generator.py (100%) rename {datasets => examples/datasets}/hed/BK.pl (100%) rename {datasets => examples/datasets}/hed/README.md (100%) rename {datasets => examples/datasets}/hed/get_hed.py (100%) rename {datasets => examples/datasets}/hed/learn_add.pl (100%) rename {datasets => examples/datasets}/hwf/README.md (100%) rename {datasets => examples/datasets}/hwf/get_hwf.py (100%) rename {datasets => examples/datasets}/mnist_add/get_mnist_add.py (100%) rename {datasets => examples/datasets}/mnist_add/test_data.txt (100%) rename {datasets => examples/datasets}/mnist_add/train_data.txt (100%) rename example.py => examples/example.py (100%) rename nonshare_example.py => examples/nonshare_example.py (100%) rename share_example.py => examples/share_example.py (100%) create mode 100644 examples/weights/all_weights_here.txt diff --git a/weights/all_weights_here.txt b/abl/__init__.py similarity index 100% rename from weights/all_weights_here.txt rename to abl/__init__.py diff --git a/abl/abducer/__init__.py b/abl/abducer/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/abducer/abducer_base.py b/abl/abducer/abducer_base.py similarity index 98% rename from abducer/abducer_base.py rename to abl/abducer/abducer_base.py index c0fd102..9a483c9 100644 --- a/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -10,16 +10,17 @@ # # ================================================================# -import sys +# import sys -sys.path.append(".") -sys.path.append("..") +# sys.path.append(".") +# sys.path.append("..") import abc -from abducer.kb import * +# TODO å°½é‡åˆ«ç”¨import * +from .kb import * import numpy as np from zoopt import Dimension, Objective, Parameter, Opt -from utils.utils import confidence_dist, flatten, hamming_dist +from ..utils.utils import confidence_dist, flatten, hamming_dist import math import time diff --git a/abducer/kb.py b/abl/abducer/kb.py similarity index 99% rename from abducer/kb.py rename to abl/abducer/kb.py index bbd6c93..8fb727c 100644 --- a/abducer/kb.py +++ b/abl/abducer/kb.py @@ -21,7 +21,7 @@ sys.path.append("..") from collections import defaultdict from itertools import product, combinations -from utils.utils import flatten, reform_idx, hamming_dist, check_equal +from ..utils.utils import flatten, reform_idx, hamming_dist, check_equal from multiprocessing import Pool @@ -299,7 +299,7 @@ class add_prolog_KB(prolog_KB): class HED_prolog_KB(prolog_KB): def __init__(self, pseudo_label_list=[0, 1, '+', '=']): super().__init__(pseudo_label_list) - self.prolog.consult('./datasets/hed/learn_add.pl') + self.prolog.consult('../examples/datasets/hed/learn_add.pl') # corresponding to `con_sol is not None` in `consistent_score_mapped` within `learn_add.py` def logic_forward(self, exs): diff --git a/framework.py b/abl/framework.py similarity index 98% rename from framework.py rename to abl/framework.py index 2a1fdad..c3a5c6e 100644 --- a/framework.py +++ b/abl/framework.py @@ -14,7 +14,7 @@ import pickle as pk import numpy as np -from utils.plog import INFO, DEBUG, clocker +from .utils.plog import INFO, DEBUG, clocker def block_sample(X, Z, Y, sample_num, epoch_idx): part_num = (len(X) // sample_num) diff --git a/framework_hed.py b/abl/framework_hed.py similarity index 97% rename from framework_hed.py rename to abl/framework_hed.py index b7439c3..d942be6 100644 --- a/framework_hed.py +++ b/abl/framework_hed.py @@ -16,12 +16,15 @@ import torch.nn as nn import numpy as np import os -from utils.plog import INFO, DEBUG, clocker -from utils.utils import flatten, reform_idx, block_sample, gen_mappings, mapping_res, remapping_res +from .utils.plog import INFO, DEBUG, clocker +from .utils.utils import flatten, reform_idx, block_sample, gen_mappings, mapping_res, remapping_res -from models.nn import MLP, SymbolNetAutoencoder -from models.basic_model import BasicModel, BasicDataset -from datasets.hed.get_hed import get_pretrain_data +from .models.nn import MLP, SymbolNetAutoencoder +from .models.basic_model import BasicModel, BasicDataset + +import sys +sys.path.append("..") +from examples.datasets.hed.get_hed import get_pretrain_data def result_statistics(pred_Z, Z, Y, logic_forward, char_acc_flag): result = {} diff --git a/abl/models/__init__.py b/abl/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/models/basic_model.py b/abl/models/basic_model.py similarity index 100% rename from models/basic_model.py rename to abl/models/basic_model.py diff --git a/models/lenet5.py b/abl/models/lenet5.py similarity index 100% rename from models/lenet5.py rename to abl/models/lenet5.py diff --git a/models/nn.py b/abl/models/nn.py similarity index 97% rename from models/nn.py rename to abl/models/nn.py index cecbeea..7a0f560 100644 --- a/models/nn.py +++ b/abl/models/nn.py @@ -10,9 +10,6 @@ # # ================================================================# -import sys - -sys.path.append("..") import torchvision @@ -23,8 +20,6 @@ from torch.autograd import Variable import torchvision.transforms as transforms import numpy as np -from models.basic_model import BasicModel -import utils.plog as plog class LeNet5(nn.Module): diff --git a/models/wabl_models.py b/abl/models/wabl_models.py similarity index 99% rename from models/wabl_models.py rename to abl/models/wabl_models.py index 9c97bbc..3b682ee 100644 --- a/models/wabl_models.py +++ b/abl/models/wabl_models.py @@ -21,7 +21,6 @@ from sklearn.preprocessing import StandardScaler from sklearn.svm import SVC from sklearn.gaussian_process import GaussianProcessClassifier from sklearn.gaussian_process.kernels import RBF -from models.basic_model import BasicModel import pickle as pk import random diff --git a/utils/plog.py b/abl/utils/plog.py similarity index 100% rename from utils/plog.py rename to abl/utils/plog.py diff --git a/utils/utils.py b/abl/utils/utils.py similarity index 98% rename from utils/utils.py rename to abl/utils/utils.py index 1138361..65c85fc 100644 --- a/utils/utils.py +++ b/abl/utils/utils.py @@ -1,5 +1,5 @@ import numpy as np -from utils.plog import INFO +from .plog import INFO from collections import OrderedDict # for multiple predictions, modify from `learn_add.py` diff --git a/datasets/data_generator.py b/examples/datasets/data_generator.py similarity index 100% rename from datasets/data_generator.py rename to examples/datasets/data_generator.py diff --git a/datasets/hed/BK.pl b/examples/datasets/hed/BK.pl similarity index 100% rename from datasets/hed/BK.pl rename to examples/datasets/hed/BK.pl diff --git a/datasets/hed/README.md b/examples/datasets/hed/README.md similarity index 100% rename from datasets/hed/README.md rename to examples/datasets/hed/README.md diff --git a/datasets/hed/get_hed.py b/examples/datasets/hed/get_hed.py similarity index 100% rename from datasets/hed/get_hed.py rename to examples/datasets/hed/get_hed.py diff --git a/datasets/hed/learn_add.pl b/examples/datasets/hed/learn_add.pl similarity index 100% rename from datasets/hed/learn_add.pl rename to examples/datasets/hed/learn_add.pl diff --git a/datasets/hwf/README.md b/examples/datasets/hwf/README.md similarity index 100% rename from datasets/hwf/README.md rename to examples/datasets/hwf/README.md diff --git a/datasets/hwf/get_hwf.py b/examples/datasets/hwf/get_hwf.py similarity index 100% rename from datasets/hwf/get_hwf.py rename to examples/datasets/hwf/get_hwf.py diff --git a/datasets/mnist_add/get_mnist_add.py b/examples/datasets/mnist_add/get_mnist_add.py similarity index 100% rename from datasets/mnist_add/get_mnist_add.py rename to examples/datasets/mnist_add/get_mnist_add.py diff --git a/datasets/mnist_add/test_data.txt b/examples/datasets/mnist_add/test_data.txt similarity index 100% rename from datasets/mnist_add/test_data.txt rename to examples/datasets/mnist_add/test_data.txt diff --git a/datasets/mnist_add/train_data.txt b/examples/datasets/mnist_add/train_data.txt similarity index 100% rename from datasets/mnist_add/train_data.txt rename to examples/datasets/mnist_add/train_data.txt diff --git a/example.py b/examples/example.py similarity index 100% rename from example.py rename to examples/example.py diff --git a/nonshare_example.py b/examples/nonshare_example.py similarity index 100% rename from nonshare_example.py rename to examples/nonshare_example.py diff --git a/share_example.py b/examples/share_example.py similarity index 100% rename from share_example.py rename to examples/share_example.py diff --git a/examples/weights/all_weights_here.txt b/examples/weights/all_weights_here.txt new file mode 100644 index 0000000..e69de29 From fe33d3b4eae6c7156c8984d20de8d10ad61cc8c7 Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Fri, 3 Mar 2023 15:31:08 +0800 Subject: [PATCH 152/601] remove unnecessary lines --- abl/abducer/kb.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 8fb727c..9a66922 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -15,10 +15,6 @@ import bisect import copy import numpy as np -import sys - -sys.path.append("..") - from collections import defaultdict from itertools import product, combinations from ..utils.utils import flatten, reform_idx, hamming_dist, check_equal From 7e4102c7091489e97648ff1f6b005f8d89f960c8 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 3 Mar 2023 16:22:36 +0800 Subject: [PATCH 153/601] Update kb.py --- abl/abducer/kb.py | 373 +++++++++++++++++++++++++++++----------------- 1 file changed, 239 insertions(+), 134 deletions(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 9a66922..66a134f 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -31,6 +31,15 @@ class KBBase(ABC): @abstractmethod def logic_forward(self): pass + + def _logic_forward(self, xs, multiple_predictions=False): + if not multiple_predictions: + return self.logic_forward(xs) + else: + res = [] + for x in xs: + res.append(self.logic_forward(x)) + return res @abstractmethod def abduce_candidates(self): @@ -40,7 +49,7 @@ class KBBase(ABC): def address_by_idx(self): pass - def _address(self, address_num, pred_res, key, multiple_predictions=False): + def _address(self, address_num, pred_res, key, multiple_predictions): new_candidates = [] if not multiple_predictions: address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) @@ -52,12 +61,12 @@ class KBBase(ABC): new_candidates += candidates return new_candidates - def _abduce_by_search(self, pred_res, key, max_address_num, require_more_address=0, multiple_predictions=False): + def _abduce_by_search(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): candidates = [] for address_num in range(len(flatten(pred_res)) + 1): if address_num == 0: - if check_equal(self.logic_forward(pred_res), key): + if check_equal(self._logic_forward(pred_res, multiple_predictions), key, self.max_err): candidates.append(pred_res) else: new_candidates = self._address(address_num, pred_res, key, multiple_predictions) @@ -88,16 +97,14 @@ class ClsKB(KBBase): self.GKB_flag = GKB_flag self.pseudo_label_list = pseudo_label_list self.len_list = len_list + self.max_err = 0 if GKB_flag: self.base = {} X, Y = self._get_GKB() for x, y in zip(X, Y): self.base.setdefault(len(x), defaultdict(list))[y].append(x) - else: - self.all_address_candidate_dict = {} - for address_num in range(max(self.len_list) + 1): - self.all_address_candidate_dict[address_num] = list(product(self.pseudo_label_list, repeat=address_num)) + # For parallel version of _get_GKB def _get_XY_list(self, args): @@ -133,33 +140,57 @@ class ClsKB(KBBase): def abduce_candidates(self, pred_res, key, max_address_num=-1, require_more_address=0, multiple_predictions=False): if self.GKB_flag: - # TODO: 这里有å¯èƒ½æ˜¯multiple_predictionså— - return self._abduce_by_GKB(pred_res, key, max_address_num, require_more_address) + return self._abduce_by_GKB(pred_res, key, max_address_num, require_more_address, multiple_predictions) else: return self._abduce_by_search(pred_res, key, max_address_num, require_more_address, multiple_predictions) - def _abduce_by_GKB(self, pred_res, key, max_address_num, require_more_address): - if self.base == {} or len(pred_res) not in self.len_list: - return [] - - all_candidates = self.base[len(pred_res)][key] + def _abduce_by_GKB(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): + if self.base == {}: + return [], 0, 0 - if len(all_candidates) == 0: - candidates = [] - min_address_num = 0 - address_num = 0 + if not multiple_predictions: + if len(pred_res) not in self.len_list: + return [], 0, 0 + all_candidates = self.base[len(pred_res)][key] + if len(all_candidates) == 0: + return [], 0, 0 + else: + cost_list = hamming_dist(pred_res, all_candidates) + min_address_num = np.min(cost_list) + address_num = min(max_address_num, min_address_num + require_more_address) + idxs = np.where(cost_list <= address_num)[0] + candidates = [all_candidates[idx] for idx in idxs] + return candidates, min_address_num, address_num + else: - cost_list = hamming_dist(pred_res, all_candidates) - min_address_num = np.min(cost_list) + min_address_num = 0 + all_candidates_save = [] + cost_list_save = [] + + for p_res, k in zip(pred_res, key): + if len(p_res) not in self.len_list: + return [], 0, 0 + all_candidates = self.base[len(p_res)][k] + if len(all_candidates) == 0: + return [], 0, 0 + else: + all_candidates_save.append(all_candidates) + cost_list = hamming_dist(p_res, all_candidates) + min_address_num += np.min(cost_list) + cost_list_save.append(cost_list) + + multiple_all_candidates = [flatten(c) for c in product(*all_candidates_save)] + assert len(multiple_all_candidates[0]) == len(flatten(pred_res)) + multiple_cost_list = np.array([sum(cost) for cost in product(*cost_list_save)]) + assert len(multiple_all_candidates) == len(multiple_cost_list) address_num = min(max_address_num, min_address_num + require_more_address) - idxs = np.where(cost_list <= address_num)[0] - candidates = [all_candidates[idx] for idx in idxs] - - return candidates, min_address_num, address_num + idxs = np.where(multiple_cost_list <= address_num)[0] + candidates = [reform_idx(multiple_all_candidates[idx], pred_res) for idx in idxs] + return candidates, min_address_num, address_num def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): candidates = [] - abduce_c = self.all_address_candidate_dict[len(address_idx)] + abduce_c = list(product(self.pseudo_label_list, repeat=len(address_idx))) if multiple_predictions: save_pred_res = pred_res @@ -173,7 +204,7 @@ class ClsKB(KBBase): if multiple_predictions: candidate = reform_idx(candidate, save_pred_res) - if self.logic_forward(candidate) == key: + if check_equal(self._logic_forward(candidate, multiple_predictions), key): candidates.append(candidate) return candidates @@ -197,50 +228,13 @@ class add_KB(ClsKB): def logic_forward(self, nums): return sum(nums) -# TODO:这是个回归任务(对于y而言),在logic_forward加roundå˜æˆç¦»æ•£çš„分类任务固然å¯è¡Œï¼Œä½†æœ€å¥½è¿˜æ˜¯ç”¨RegKBå§ï¼Œä½œä¸ºä¾‹å­ç¤ºèŒƒã€‚还需è¦å¯¹ä¸‹é¢çš„ClsKB进行修改(è§TODO) -class HWF_KB(ClsKB): - def __init__( - self, GKB_flag=False, pseudo_label_list=['1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', 'times', 'div'], len_list=[1, 3, 5, 7] - ): - super().__init__(GKB_flag, pseudo_label_list, len_list) - - def valid_candidate(self, formula): - if len(formula) % 2 == 0: - return False - for i in range(len(formula)): - if i % 2 == 0 and formula[i] not in ['1', '2', '3', '4', '5', '6', '7', '8', '9']: - return False - if i % 2 != 0 and formula[i] not in ['+', '-', 'times', 'div']: - return False - return True - - def logic_forward(self, formula): - if not self.valid_candidate(formula): - return np.inf - mapping = { - '1': '1', - '2': '2', - '3': '3', - '4': '4', - '5': '5', - '6': '6', - '7': '7', - '8': '8', - '9': '9', - '+': '+', - '-': '-', - 'times': '*', - 'div': '/', - } - formula = [mapping[f] for f in formula] - return round(eval(''.join(formula)), 2) - class prolog_KB(KBBase): def __init__(self, pseudo_label_list): super().__init__() self.pseudo_label_list = pseudo_label_list self.prolog = pyswip.Prolog() + self.max_err = 0 def logic_forward(self): pass @@ -295,11 +289,11 @@ class add_prolog_KB(prolog_KB): class HED_prolog_KB(prolog_KB): def __init__(self, pseudo_label_list=[0, 1, '+', '=']): super().__init__(pseudo_label_list) - self.prolog.consult('../examples/datasets/hed/learn_add.pl') + self.prolog.consult('./datasets/hed/learn_add.pl') # corresponding to `con_sol is not None` in `consistent_score_mapped` within `learn_add.py` def logic_forward(self, exs): - return len(list(self.prolog.query("abduce_consistent_insts(%s)." % exs))) != 0 + return len(list(self.prolog.query("abduce_consistent_insts([%s])." % exs))) != 0 def get_query_string_need_flatten(self, pred_res, key, address_idx): # flatten @@ -329,93 +323,204 @@ class HED_prolog_KB(prolog_KB): rules.append(rule.value) return rules - # def consist_rules(self, pred_res, rules): -# TODO:这里需è¦ä¿®æ”¹ä¸€ä¸‹è¿™ä¸ªç±»ï¼ŒåŽŸæœ¬çš„RegKB是对GKB而言的,现在需è¦å’ŒClsKBä¸€æ ·åŒæ—¶æ”¯æŒGKBå’ŒéžGKB。需è¦è¡¥å……éžGKB部分(å¯èƒ½ç»§æ‰¿_abduce_by_search就行),以åŠä¿®æ”¹GKB部分_abduce_by_GKB的逻辑(原本逻辑是找与key最近的yçš„abduce结果,现在改æˆä¸Žkey在一定误差范围内的yçš„abduce结果) -# TODO:我ç†è§£çš„RegKB是这样的: -# TODO:1. 对GKB而言,å³_abduce_by_GKB,给定keyå’Œlength,还需è¦ä¸€ä¸ªself.max_err,返回所有与keyç»å¯¹å€¼å°äºŽmax_errçš„abduction结果 -# TODO:比如GKB里的y有[1.3, 1.49, 1.50, 1.52, 1.6],若key=1.5,max_err=1e-5,则返回[y=1.50]çš„abduction结果;若key=1.5,max_err=0.05,则返回所有[y=1.49, 1.50, 1.52]çš„abduction结果 -# TODO:因此在二分查找bisect_leftåŽï¼Œéœ€è¦åˆ†åˆ«å¾€å‰å’Œå¾€åŽé历,从GKB里找符åˆè¯¯å·®çš„y -# TODO:self.max_err默认值å–很å°å°±è¡Œï¼Œæ¯”如HWF这类任务;但有些任务(比如法院刑期预测)的max_err需è¦å¤§äº›ï¼Œå› æ­¤å¯ä»¥ç”±ç”¨æˆ·è‡ªå®šä¹‰ -# TODO:2. 对éžGKB而言,估计直接用_abduce_by_search就行,check_equalé‚£é™å®šä¸ºæ•°å­—且控制回归误差max_err class RegKB(KBBase): - def __init__(self, GKB_flag=False, X=None, Y=None): + def __init__(self, GKB_flag=False, pseudo_label_list=None, len_list=None, max_err=1e-3): super().__init__() - tmp_dict = {} - for x, y in zip(X, Y): - tmp_dict.setdefault(len(x), defaultdict(list))[y].append(np.array(x)) - - self.base = {} - for l in tmp_dict.keys(): - data = sorted(list(zip(tmp_dict[l].keys(), tmp_dict[l].values()))) - X = [x for y, x in data] - Y = [y for y, x in data] - self.base[l] = (X, Y) - - def valid_candidate(self): - pass + self.GKB_flag = GKB_flag + self.pseudo_label_list = pseudo_label_list + self.len_list = len_list + self.max_err = max_err + + if GKB_flag: + self.base = {} + X, Y = self._get_GKB() + for x, y in zip(X, Y): + self.base.setdefault(len(x), defaultdict(list))[y].append(x) + + # For parallel version of _get_GKB + def _get_XY_list(self, args): + pre_x, post_x_it = args[0], args[1] + XY_list = [] + for post_x in post_x_it: + x = (pre_x,) + post_x + y = self.logic_forward(x) + if y != np.inf: + XY_list.append((x, y)) + return XY_list + + # Parallel _get_GKB + def _get_GKB(self): + X, Y = [], [] + for length in self.len_list: + arg_list = [] + for pre_x in self.pseudo_label_list: + post_x_it = product(self.pseudo_label_list, repeat=length - 1) + arg_list.append((pre_x, post_x_it)) + with Pool(processes=len(arg_list)) as pool: + ret_list = pool.map(self._get_XY_list, arg_list) + for XY_list in ret_list: + if len(XY_list) == 0: + continue + part_X, part_Y = zip(*XY_list) + X.extend(part_X) + Y.extend(part_Y) + return X, Y def logic_forward(self): pass - def _abduce_by_GKB(self, key, length=None): - if key is None: - return self.get_all_candidates() + def abduce_candidates(self, pred_res, key, max_address_num=-1, require_more_address=0, multiple_predictions=False): + if self.GKB_flag: + return self._abduce_by_GKB(pred_res, key, max_address_num, require_more_address, multiple_predictions) + else: + return self._abduce_by_search(pred_res, key, max_address_num, require_more_address, multiple_predictions) - length = self._length(length) + def _regression_find_candidate_GKB(self, pred_res, key): + potential_candidates = self.base[len(pred_res)] + key_list = sorted(potential_candidates) + key_idx = bisect.bisect_left(key_list, key) + + all_candidates = [] + for idx in range(key_idx - 1, 0, -1): + k = key_list[idx] + if abs(k - key) <= self.max_err: + all_candidates += potential_candidates[k] + else: + break + + for idx in range(key_idx, len(key_list)): + k = key_list[idx] + if abs(k - key) <= self.max_err: + all_candidates += potential_candidates[k] + else: + break + return all_candidates + + def _abduce_by_GKB(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): + if self.base == {}: + return [], 0, 0 - min_err = 999999 + if not multiple_predictions: + if len(pred_res) not in self.len_list: + return [], 0, 0 + all_candidates = self._regression_find_candidate_GKB(pred_res, key) + if len(all_candidates) == 0: + return [], 0, 0 + else: + cost_list = hamming_dist(pred_res, all_candidates) + min_address_num = np.min(cost_list) + address_num = min(max_address_num, min_address_num + require_more_address) + idxs = np.where(cost_list <= address_num)[0] + candidates = [all_candidates[idx] for idx in idxs] + return candidates, min_address_num, address_num + + else: + min_address_num = 0 + all_candidates_save = [] + cost_list_save = [] + + for p_res, k in zip(pred_res, key): + if len(p_res) not in self.len_list: + return [], 0, 0 + all_candidates = self._regression_find_candidate_GKB(p_res, k) + if len(all_candidates) == 0: + return [], 0, 0 + else: + all_candidates_save.append(all_candidates) + cost_list = hamming_dist(p_res, all_candidates) + min_address_num += np.min(cost_list) + cost_list_save.append(cost_list) + + multiple_all_candidates = [flatten(c) for c in product(*all_candidates_save)] + assert len(multiple_all_candidates[0]) == len(flatten(pred_res)) + multiple_cost_list = np.array([sum(cost) for cost in product(*cost_list_save)]) + assert len(multiple_all_candidates) == len(multiple_cost_list) + address_num = min(max_address_num, min_address_num + require_more_address) + idxs = np.where(multiple_cost_list <= address_num)[0] + candidates = [reform_idx(multiple_all_candidates[idx], pred_res) for idx in idxs] + return candidates, min_address_num, address_num + + def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): candidates = [] - for l in length: - X, Y = self.base[l] - - idx = bisect.bisect_left(Y, key) - begin = max(0, idx - 1) - end = min(idx + 2, len(X)) - - for idx in range(begin, end): - err = abs(Y[idx] - key) - if abs(err - min_err) < 1e-9: - candidates.extend(X[idx]) - elif err < min_err: - candidates = copy.deepcopy(X[idx]) - min_err = err - return candidates + abduce_c = list(product(self.pseudo_label_list, repeat=len(address_idx))) - def get_all_candidates(self): - return sum([sum(D[0], []) for D in self.base.values()], []) + if multiple_predictions: + save_pred_res = pred_res + pred_res = flatten(pred_res) + + for c in abduce_c: + candidate = pred_res.copy() + for i, idx in enumerate(address_idx): + candidate[idx] = c[i] + + if multiple_predictions: + candidate = reform_idx(candidate, save_pred_res) + + if check_equal(self._logic_forward(candidate, multiple_predictions), key, self.max_err): + candidates.append(candidate) + return candidates + + def _dict_len(self, dic): + if not self.GKB_flag: + return 0 + else: + return sum(len(c) for c in dic.values()) def __len__(self): - return sum([sum(len(x) for x in D[0]) for D in self.base.values()]) + if not self.GKB_flag: + return 0 + else: + return sum(self._dict_len(v) for v in self.base.values()) + + +class HWF_KB(RegKB): + def __init__( + self, GKB_flag=False, + pseudo_label_list=['1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', 'times', 'div'], + len_list=[1, 3, 5, 7], + max_err=1e-3 + ): + super().__init__(GKB_flag, pseudo_label_list, len_list, max_err) + + def valid_candidate(self, formula): + if len(formula) % 2 == 0: + return False + for i in range(len(formula)): + if i % 2 == 0 and formula[i] not in ['1', '2', '3', '4', '5', '6', '7', '8', '9']: + return False + if i % 2 != 0 and formula[i] not in ['+', '-', 'times', 'div']: + return False + return True + + def logic_forward(self, formula): + if not self.valid_candidate(formula): + return np.inf + mapping = { + '1': '1', + '2': '2', + '3': '3', + '4': '4', + '5': '5', + '6': '6', + '7': '7', + '8': '8', + '9': '9', + '+': '+', + '-': '-', + 'times': '*', + 'div': '/', + } + formula = [mapping[f] for f in formula] + return round(eval(''.join(formula)), 2) import time if __name__ == "__main__": t1 = time.time() - kb = HWF_KB(True) + kb = add_KB(True) t2 = time.time() print(t2 - t1) - # X = ["1+1", "0+1", "1+0", "2+0", "1+0+1"] - # Y = [2, 1, 1, 2, 2] - # kb = ClsKB(X, Y) - # print('len(kb):', len(kb)) - # res = kb.get_candidates(2, 5) - # print(res) - # res = kb.get_candidates(2, 3) - # print(res) - # res = kb.get_candidates(None) - # print(res) - # print() - - # X = ["1+1", "0+1", "1+0", "2+0", "1+0.5", "0.75+0.75"] - # Y = [2, 1, 1, 2, 1.5, 1.5] - # kb = RegKB(X, Y) - # print('len(kb):', len(kb)) - # res = kb.get_candidates(1.6) - # print(res) - # res = kb.get_candidates(1.6, length = 9) - # print(res) - # res = kb.get_candidates(None) - # print(res) + From 09083f9c2e847ddc290522db02db1212e8da4be8 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 3 Mar 2023 16:24:12 +0800 Subject: [PATCH 154/601] Update abducer_base.py --- abl/abducer/abducer_base.py | 192 +++++++++++++++++------------------- 1 file changed, 90 insertions(+), 102 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index 9a483c9..811f0ea 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -10,33 +10,16 @@ # # ================================================================# -# import sys - -# sys.path.append(".") -# sys.path.append("..") - import abc -# TODO å°½é‡åˆ«ç”¨import * from .kb import * import numpy as np from zoopt import Dimension, Objective, Parameter, Opt from ..utils.utils import confidence_dist, flatten, hamming_dist -import math -import time - - class AbducerBase(abc.ABC): - def __init__( - self, - kb, - dist_func="confidence", - zoopt=False, - multiple_predictions=False, - cache=True, - ): + def __init__(self, kb, dist_func='confidence', zoopt=False, multiple_predictions=False, cache=True): self.kb = kb - assert dist_func == "hamming" or dist_func == "confidence" + assert dist_func == 'hamming' or dist_func == 'confidence' self.dist_func = dist_func self.zoopt = zoopt self.multiple_predictions = multiple_predictions @@ -47,41 +30,42 @@ class AbducerBase(abc.ABC): self.cache_candidates = {} def _get_cost_list(self, pred_res, pred_res_prob, candidates): - if self.dist_func == "hamming": + if self.dist_func == 'hamming': + if self.multiple_predictions: + pred_res = flatten(pred_res) + candidates = [flatten(c) for c in candidates] + return hamming_dist(pred_res, candidates) - elif self.dist_func == "confidence": - mapping = dict( - zip( - self.kb.pseudo_label_list, - list(range(len(self.kb.pseudo_label_list))), - ) - ) - return confidence_dist( - pred_res_prob, [list(map(lambda x: mapping[x], c)) for c in candidates] - ) + + elif self.dist_func == 'confidence': + if self.multiple_predictions: + pred_res_prob = flatten(pred_res_prob) + candidates = [flatten(c) for c in candidates] + + mapping = dict(zip(self.kb.pseudo_label_list, list(range(len(self.kb.pseudo_label_list))))) + candidates = [list(map(lambda x: mapping[x], c)) for c in candidates] + return confidence_dist(pred_res_prob, candidates) def _get_one_candidate(self, pred_res, pred_res_prob, candidates): if len(candidates) == 0: return [] elif len(candidates) == 1 or self.zoopt: return candidates[0] + else: cost_list = self._get_cost_list(pred_res, pred_res_prob, candidates) min_address_num = np.min(cost_list) idxs = np.where(cost_list == min_address_num)[0] - return [candidates[idx] for idx in idxs][0] + candidate = [candidates[idx] for idx in idxs][0] + return candidate # for zoopt def _zoopt_score_multiple(self, pred_res, key, solution): all_address_flag = reform_idx(solution, pred_res) score = 0 for idx in range(len(pred_res)): - address_idx = [ - i for i, flag in enumerate(all_address_flag[idx]) if flag != 0 - ] - candidate = self.kb.address_by_idx( - [pred_res[idx]], key[idx], address_idx, True - ) + address_idx = [i for i, flag in enumerate(all_address_flag[idx]) if flag != 0] + candidate = self.kb.address_by_idx([pred_res[idx]], key[idx], address_idx, True) if len(candidate) > 0: score += 1 return score @@ -89,9 +73,7 @@ class AbducerBase(abc.ABC): def _zoopt_address_score(self, pred_res, key, sol): if not self.multiple_predictions: address_idx = [idx for idx, i in enumerate(sol.get_x()) if i != 0] - candidates = self.kb.address_by_idx( - pred_res, key, address_idx, self.multiple_predictions - ) + candidates = self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) return 1 if len(candidates) > 0 else 0 else: return self._zoopt_score_multiple(pred_res, key, sol.get_x()) @@ -108,7 +90,7 @@ class AbducerBase(abc.ABC): dim=dimension, constraint=lambda sol: self._constrain_address_num(sol, max_address_num), ) - parameter = Parameter(budget=100, autoset=True) + parameter = Parameter(budget=100, intermediate_result=False, autoset=True) solution = Opt.min(objective, parameter).get_x() return solution @@ -119,11 +101,7 @@ class AbducerBase(abc.ABC): pred_res = flatten(pred_res) key = tuple(key) if (tuple(pred_res), key) in self.cache_min_address_num: - address_num = min( - max_address_num, - self.cache_min_address_num[(tuple(pred_res), key)] - + require_more_address, - ) + address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), key)] + require_more_address) if (tuple(pred_res), key, address_num) in self.cache_candidates: candidates = self.cache_candidates[(tuple(pred_res), key, address_num)] if self.zoopt: @@ -152,18 +130,12 @@ class AbducerBase(abc.ABC): if self.zoopt: solution = self.zoopt_get_solution(pred_res, key, max_address_num) address_idx = [idx for idx, i in enumerate(solution) if i != 0] - candidates = self.kb.address_by_idx( - pred_res, key, address_idx, self.multiple_predictions - ) + candidates = self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) address_num = int(solution.sum()) min_address_num = address_num else: candidates, min_address_num, address_num = self.kb.abduce_candidates( - pred_res, - key, - max_address_num, - require_more_address, - self.multiple_predictions, + pred_res, key, max_address_num, require_more_address, self.multiple_predictions ) candidate = self._get_one_candidate(pred_res, pred_res_prob, candidates) @@ -177,32 +149,21 @@ class AbducerBase(abc.ABC): return self.kb.abduce_rules(pred_res) def batch_abduce(self, Z, Y, max_address_num=-1, require_more_address=0): - if self.multiple_predictions: - return self.abduce( - (Z["cls"], Z["prob"], Y), max_address_num, require_more_address - ) - else: - return [ - self.abduce((z, prob, y), max_address_num, require_more_address) - for z, prob, y in zip(Z["cls"], Z["prob"], Y) - ] + # if self.multiple_predictions: + return self.abduce((Z['cls'], Z['prob'], Y), max_address_num, require_more_address) + # else: + # return [self.abduce((z, prob, y), max_address_num, require_more_address) for z, prob, y in zip(Z['cls'], Z['prob'], Y)] def __call__(self, Z, Y, max_address_num=-1, require_more_address=0): return self.batch_abduce(Z, Y, max_address_num, require_more_address) -if __name__ == "__main__": - prob1 = [ - [0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], - [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], - ] - prob2 = [ - [0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], - [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], - ] +if __name__ == '__main__': + prob1 = [[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] + prob2 = [[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] - kb = add_KB() - abd = AbducerBase(kb, "confidence") + kb = add_KB(True) + abd = AbducerBase(kb, 'confidence') res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) print(res) res = abd.abduce(([1, 1], prob2, 8), max_address_num=2, require_more_address=0) @@ -214,9 +175,23 @@ if __name__ == "__main__": res = abd.abduce(([1, 1], prob1, 20), max_address_num=2, require_more_address=0) print(res) print() + + + multiple_prob = [[[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]], + [[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]] + + + kb = add_KB() + abd = AbducerBase(kb, 'confidence', multiple_predictions=True) + res = abd.abduce(([[1, 1], [1, 2]], multiple_prob, [4, 8]), max_address_num=4, require_more_address=0) + print(res) + res = abd.abduce(([[1, 1], [1, 2]], multiple_prob, [4, 8]), max_address_num=4, require_more_address=1) + print(res) + print() + kb = add_prolog_KB() - abd = AbducerBase(kb, "confidence") + abd = AbducerBase(kb, 'confidence') res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) print(res) res = abd.abduce(([1, 1], prob2, 8), max_address_num=2, require_more_address=0) @@ -230,7 +205,7 @@ if __name__ == "__main__": print() kb = add_prolog_KB() - abd = AbducerBase(kb, "confidence", zoopt=True) + abd = AbducerBase(kb, 'confidence', zoopt=True) res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) print(res) res = abd.abduce(([1, 1], prob2, 8), max_address_num=2, require_more_address=0) @@ -243,42 +218,55 @@ if __name__ == "__main__": print(res) print() - kb = HWF_KB(len_list=[1, 3, 5]) - abd = AbducerBase(kb, "hamming") - res = abd.abduce( - (["5", "+", "2"], None, 3), max_address_num=2, require_more_address=0 - ) + kb = HWF_KB(True, len_list=[1, 3, 5], max_err = 0.1) + abd = AbducerBase(kb, 'hamming') + res = abd.abduce((['5', '+', '2'], None, 3), max_address_num=2, require_more_address=0) + print(res) + res = abd.abduce((['5', '+', '9'], None, 64), max_address_num=3, require_more_address=0) + print(res) + + kb = HWF_KB(True, len_list=[1, 3, 5], max_err = 1) + abd = AbducerBase(kb, 'hamming') + res = abd.abduce((['5', '+', '9'], None, 64), max_address_num=3, require_more_address=0) + print(res) + res = abd.abduce((['5', '+', '2'], None, 1.67), max_address_num=3, require_more_address=0) + print(res) + res = abd.abduce((['5', '8', '8', '8', '8'], None, 3.17), max_address_num=5, require_more_address=3) + print(res) + print() + + kb = HWF_KB(len_list=[1, 3, 5], max_err = 0.1) + abd = AbducerBase(kb, 'hamming', multiple_predictions=True) + res = abd.abduce(([['5', '+', '2'], ['5', '+', '9']], None, [3, 64]), max_address_num=6, require_more_address=0) + print(res) + print() + + kb = HWF_KB(len_list=[1, 3, 5], max_err = 0.1) + abd = AbducerBase(kb, 'hamming') + res = abd.abduce((['5', '+', '2'], None, 3), max_address_num=2, require_more_address=0) + print(res) + res = abd.abduce((['5', '+', '9'], None, 64), max_address_num=3, require_more_address=0) print(res) - res = abd.abduce( - (["5", "+", "2"], None, 64), max_address_num=3, require_more_address=0 - ) + + kb = HWF_KB(len_list=[1, 3, 5], max_err = 1) + abd = AbducerBase(kb, 'hamming') + res = abd.abduce((['5', '+', '9'], None, 64), max_address_num=3, require_more_address=0) print(res) - res = abd.abduce( - (["5", "+", "2"], None, 1.67), max_address_num=3, require_more_address=0 - ) + res = abd.abduce((['5', '+', '2'], None, 1.67), max_address_num=3, require_more_address=0) print(res) - res = abd.abduce( - (["5", "8", "8", "8", "8"], None, 3.17), - max_address_num=5, - require_more_address=3, - ) + res = abd.abduce((['5', '8', '8', '8', '8'], None, 3.17), max_address_num=5, require_more_address=3) print(res) print() kb = HED_prolog_KB() abd = AbducerBase(kb, zoopt=True, multiple_predictions=True) - consist_exs = [[1, "+", 0, "=", 0], [1, "+", 1, "=", 0], [0, "+", 0, "=", 1, 1]] - consist_exs2 = [ - [1, "+", 0, "=", 0], - [1, "+", 1, "=", 0], - [0, "+", 1, "=", 1, 1], - ] # not consistent with rules - inconsist_exs = [[1, "+", 0, "=", 0], [1, "=", 1, "=", 0], [0, "=", 0, "=", 1, 1]] + consist_exs = [[1, 1, '+', 0, '=', 1, 1], [1, '+', 1, '=', 1, 0], [0, '+', 0, '=', 0]] + inconsist_exs = [[1, '+', 0, '=', 0], [1, '=', 1, '=', 0], [0, '=', 0, '=', 1, 1]] # inconsist_exs = [[1, '+', 0, '=', 0], ['=', '=', '=', '=', 0], ['=', '=', 0, '=', '=', '=']] - rules = ["my_op([0], [0], [1, 1])", "my_op([1], [1], [0])", "my_op([1], [0], [0])"] + rules = ['my_op([0], [0], [0])', 'my_op([1], [1], [1, 0])'] - print(kb.logic_forward(consist_exs), kb.logic_forward(inconsist_exs)) - print(kb.consist_rule(consist_exs, rules), kb.consist_rule(consist_exs2, rules)) + print(kb._logic_forward(consist_exs, True), kb._logic_forward(inconsist_exs, True)) + print(kb.consist_rule([1, '+', 1, '=', 1, 0], rules), kb.consist_rule([1, '+', 1, '=', 1, 1], rules)) print() res = abd.abduce((consist_exs, None, [1] * len(consist_exs))) From 6ead422a1c8f0a12117370b6d83e79ca3dd8a229 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 3 Mar 2023 16:24:43 +0800 Subject: [PATCH 155/601] Update utils.py --- abl/utils/utils.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/abl/utils/utils.py b/abl/utils/utils.py index 65c85fc..05b97a4 100644 --- a/abl/utils/utils.py +++ b/abl/utils/utils.py @@ -4,7 +4,10 @@ from collections import OrderedDict # for multiple predictions, modify from `learn_add.py` def flatten(l): - return [item for sublist in l for item in flatten(sublist)] if isinstance(l, list) else [l] + # return [item for sublist in l for item in flatten(sublist)] if isinstance(l, (list, tuple)) else [l] + if not isinstance(l[0], (list, tuple)): + return l + return [item for sublist in l for item in sublist] if isinstance(l, (list, tuple)) else [l] # for multiple predictions, modify from `learn_add.py` def reform_idx(flatten_pred_res, save_pred_res): From af8753bdcacec34af50a39840252c6aad9c84d2b Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 3 Mar 2023 16:36:26 +0800 Subject: [PATCH 156/601] Update abducer_base.py --- abl/abducer/abducer_base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index 811f0ea..36a0e76 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -11,7 +11,6 @@ # ================================================================# import abc -from .kb import * import numpy as np from zoopt import Dimension, Objective, Parameter, Opt from ..utils.utils import confidence_dist, flatten, hamming_dist @@ -159,6 +158,8 @@ class AbducerBase(abc.ABC): if __name__ == '__main__': + from kb import add_KB, add_prolog_KB, HWF_KB, HED_prolog_KB + prob1 = [[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] prob2 = [[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] From 956d64ba1a6da8ea3ab784199df50110acc04c48 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 3 Mar 2023 16:38:25 +0800 Subject: [PATCH 157/601] Update abducer_base.py --- abl/abducer/abducer_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index 36a0e76..9fcfa0a 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -13,7 +13,7 @@ import abc import numpy as np from zoopt import Dimension, Objective, Parameter, Opt -from ..utils.utils import confidence_dist, flatten, hamming_dist +from ..utils.utils import confidence_dist, flatten, reform_idx, hamming_dist class AbducerBase(abc.ABC): def __init__(self, kb, dist_func='confidence', zoopt=False, multiple_predictions=False, cache=True): From cf15052331af5b89678cb397ffa09b98924ffa2f Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 3 Mar 2023 16:48:46 +0800 Subject: [PATCH 158/601] Update utils.py --- abl/utils/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/abl/utils/utils.py b/abl/utils/utils.py index 05b97a4..fbb5bfb 100644 --- a/abl/utils/utils.py +++ b/abl/utils/utils.py @@ -76,9 +76,9 @@ def remapping_res(pred_res, m): remapping[value] = key return [[remapping[symbol] for symbol in formula] for formula in pred_res] -def check_equal(a, b): +def check_equal(a, b, max_err=0): if isinstance(a, (int, float)) and isinstance(b, (int, float)): - return abs(a - b) <= 1e-3 + return abs(a - b) <= max_err if isinstance(a, list) and isinstance(b, list): if len(a) != len(b): @@ -89,4 +89,4 @@ def check_equal(a, b): return True else: - return a == b + return a == b From 930b549d4eab631fd700a90c1cfce867d13feb49 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 3 Mar 2023 17:01:31 +0800 Subject: [PATCH 159/601] Update kb.py --- abl/abducer/kb.py | 170 +++++++++++++++------------------------------- 1 file changed, 56 insertions(+), 114 deletions(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 66a134f..cd15dd3 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -25,8 +25,46 @@ import pyswip class KBBase(ABC): - def __init__(self, pseudo_label_list=None): - pass + def __init__(self, pseudo_label_list=None, len_list=None, GKB_flag=False, max_err=0): + self.pseudo_label_list = pseudo_label_list + self.len_list = len_list + self.GKB_flag = GKB_flag + self.max_err = max_err + + if GKB_flag: + self.base = {} + X, Y = self._get_GKB() + for x, y in zip(X, Y): + self.base.setdefault(len(x), defaultdict(list))[y].append(x) + + # For parallel version of _get_GKB + def _get_XY_list(self, args): + pre_x, post_x_it = args[0], args[1] + XY_list = [] + for post_x in post_x_it: + x = (pre_x,) + post_x + y = self.logic_forward(x) + if y != np.inf: + XY_list.append((x, y)) + return XY_list + + # Parallel _get_GKB + def _get_GKB(self): + X, Y = [], [] + for length in self.len_list: + arg_list = [] + for pre_x in self.pseudo_label_list: + post_x_it = product(self.pseudo_label_list, repeat=length - 1) + arg_list.append((pre_x, post_x_it)) + with Pool(processes=len(arg_list)) as pool: + ret_list = pool.map(self._get_XY_list, arg_list) + for XY_list in ret_list: + if len(XY_list) == 0: + continue + part_X, part_Y = zip(*XY_list) + X.extend(part_X) + Y.extend(part_Y) + return X, Y @abstractmethod def logic_forward(self): @@ -87,53 +125,22 @@ class KBBase(ABC): return candidates, min_address_num, address_num + def _dict_len(self, dic): + if not self.GKB_flag: + return 0 + else: + return sum(len(c) for c in dic.values()) + def __len__(self): - pass + if not self.GKB_flag: + return 0 + else: + return sum(self._dict_len(v) for v in self.base.values()) class ClsKB(KBBase): - def __init__(self, GKB_flag=False, pseudo_label_list=None, len_list=None): - super().__init__() - self.GKB_flag = GKB_flag - self.pseudo_label_list = pseudo_label_list - self.len_list = len_list - self.max_err = 0 - - if GKB_flag: - self.base = {} - X, Y = self._get_GKB() - for x, y in zip(X, Y): - self.base.setdefault(len(x), defaultdict(list))[y].append(x) - - - # For parallel version of _get_GKB - def _get_XY_list(self, args): - pre_x, post_x_it = args[0], args[1] - XY_list = [] - for post_x in post_x_it: - x = (pre_x,) + post_x - y = self.logic_forward(x) - if y != np.inf: - XY_list.append((x, y)) - return XY_list - - # Parallel _get_GKB - def _get_GKB(self): - X, Y = [], [] - for length in self.len_list: - arg_list = [] - for pre_x in self.pseudo_label_list: - post_x_it = product(self.pseudo_label_list, repeat=length - 1) - arg_list.append((pre_x, post_x_it)) - with Pool(processes=len(arg_list)) as pool: - ret_list = pool.map(self._get_XY_list, arg_list) - for XY_list in ret_list: - if len(XY_list) == 0: - continue - part_X, part_Y = zip(*XY_list) - X.extend(part_X) - Y.extend(part_Y) - return X, Y + def __init__(self, pseudo_label_list, len_list, GKB_flag): + super().__init__(pseudo_label_list, len_list, GKB_flag) def logic_forward(self): pass @@ -208,22 +215,10 @@ class ClsKB(KBBase): candidates.append(candidate) return candidates - def _dict_len(self, dic): - if not self.GKB_flag: - return 0 - else: - return sum(len(c) for c in dic.values()) - - def __len__(self): - if not self.GKB_flag: - return 0 - else: - return sum(self._dict_len(v) for v in self.base.values()) - class add_KB(ClsKB): - def __init__(self, GKB_flag=False, pseudo_label_list=list(range(10)), len_list=[2]): - super().__init__(GKB_flag, pseudo_label_list, len_list) + def __init__(self, pseudo_label_list=list(range(10)), len_list=[2], GKB_flag=False): + super().__init__(pseudo_label_list, len_list, GKB_flag) def logic_forward(self, nums): return sum(nums) @@ -231,10 +226,8 @@ class add_KB(ClsKB): class prolog_KB(KBBase): def __init__(self, pseudo_label_list): - super().__init__() - self.pseudo_label_list = pseudo_label_list + super().__init__(pseudo_label_list) self.prolog = pyswip.Prolog() - self.max_err = 0 def logic_forward(self): pass @@ -326,46 +319,7 @@ class HED_prolog_KB(prolog_KB): class RegKB(KBBase): def __init__(self, GKB_flag=False, pseudo_label_list=None, len_list=None, max_err=1e-3): - super().__init__() - self.GKB_flag = GKB_flag - self.pseudo_label_list = pseudo_label_list - self.len_list = len_list - self.max_err = max_err - - if GKB_flag: - self.base = {} - X, Y = self._get_GKB() - for x, y in zip(X, Y): - self.base.setdefault(len(x), defaultdict(list))[y].append(x) - - # For parallel version of _get_GKB - def _get_XY_list(self, args): - pre_x, post_x_it = args[0], args[1] - XY_list = [] - for post_x in post_x_it: - x = (pre_x,) + post_x - y = self.logic_forward(x) - if y != np.inf: - XY_list.append((x, y)) - return XY_list - - # Parallel _get_GKB - def _get_GKB(self): - X, Y = [], [] - for length in self.len_list: - arg_list = [] - for pre_x in self.pseudo_label_list: - post_x_it = product(self.pseudo_label_list, repeat=length - 1) - arg_list.append((pre_x, post_x_it)) - with Pool(processes=len(arg_list)) as pool: - ret_list = pool.map(self._get_XY_list, arg_list) - for XY_list in ret_list: - if len(XY_list) == 0: - continue - part_X, part_Y = zip(*XY_list) - X.extend(part_X) - Y.extend(part_Y) - return X, Y + super().__init__(pseudo_label_list, len_list, GKB_flag, max_err) def logic_forward(self): pass @@ -461,18 +415,6 @@ class RegKB(KBBase): candidates.append(candidate) return candidates - def _dict_len(self, dic): - if not self.GKB_flag: - return 0 - else: - return sum(len(c) for c in dic.values()) - - def __len__(self): - if not self.GKB_flag: - return 0 - else: - return sum(self._dict_len(v) for v in self.base.values()) - class HWF_KB(RegKB): def __init__( From 173138f64802a0ea02fdd2a5a51137bb68e65638 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 3 Mar 2023 17:02:04 +0800 Subject: [PATCH 160/601] Update kb.py --- abl/abducer/kb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index cd15dd3..7ac26c8 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -461,7 +461,7 @@ import time if __name__ == "__main__": t1 = time.time() - kb = add_KB(True) + kb = add_KB(GKB_flag=True) t2 = time.time() print(t2 - t1) From 4478e4e3de5ea0ea0dec93562750dc334eec5e8a Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 3 Mar 2023 18:40:15 +0800 Subject: [PATCH 161/601] Rearrange abduce_by_GKB and address_by_idx to Base --- abl/abducer/kb.py | 258 ++++++++++++++-------------------------------- 1 file changed, 80 insertions(+), 178 deletions(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 7ac26c8..7c494c5 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -10,20 +10,6 @@ # # ================================================================# -from abc import ABC, abstractmethod -import bisect -import copy -import numpy as np - -from collections import defaultdict -from itertools import product, combinations -from ..utils.utils import flatten, reform_idx, hamming_dist, check_equal - -from multiprocessing import Pool - -import pyswip - - class KBBase(ABC): def __init__(self, pseudo_label_list=None, len_list=None, GKB_flag=False, max_err=0): self.pseudo_label_list = pseudo_label_list @@ -79,78 +65,16 @@ class KBBase(ABC): res.append(self.logic_forward(x)) return res - @abstractmethod - def abduce_candidates(self): - pass - - @abstractmethod - def address_by_idx(self): - pass - - def _address(self, address_num, pred_res, key, multiple_predictions): - new_candidates = [] - if not multiple_predictions: - address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) - else: - address_idx_list = list(combinations(list(range(len(flatten(pred_res)))), address_num)) - - for address_idx in address_idx_list: - candidates = self.address_by_idx(pred_res, key, address_idx, multiple_predictions) - new_candidates += candidates - return new_candidates - - def _abduce_by_search(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): - candidates = [] - - for address_num in range(len(flatten(pred_res)) + 1): - if address_num == 0: - if check_equal(self._logic_forward(pred_res, multiple_predictions), key, self.max_err): - candidates.append(pred_res) - else: - new_candidates = self._address(address_num, pred_res, key, multiple_predictions) - candidates += new_candidates - - if len(candidates) > 0: - min_address_num = address_num - break - - if address_num >= max_address_num: - return [], 0, 0 - - for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): - if address_num > max_address_num: - return candidates, min_address_num, address_num - 1 - new_candidates = self._address(address_num, pred_res, key, multiple_predictions) - candidates += new_candidates - - return candidates, min_address_num, address_num - - def _dict_len(self, dic): - if not self.GKB_flag: - return 0 - else: - return sum(len(c) for c in dic.values()) - - def __len__(self): - if not self.GKB_flag: - return 0 - else: - return sum(self._dict_len(v) for v in self.base.values()) - - -class ClsKB(KBBase): - def __init__(self, pseudo_label_list, len_list, GKB_flag): - super().__init__(pseudo_label_list, len_list, GKB_flag) - - def logic_forward(self): - pass - def abduce_candidates(self, pred_res, key, max_address_num=-1, require_more_address=0, multiple_predictions=False): if self.GKB_flag: return self._abduce_by_GKB(pred_res, key, max_address_num, require_more_address, multiple_predictions) else: return self._abduce_by_search(pred_res, key, max_address_num, require_more_address, multiple_predictions) - + + @abstractmethod + def _find_candidate_GKB(self): + pass + def _abduce_by_GKB(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): if self.base == {}: return [], 0, 0 @@ -158,7 +82,7 @@ class ClsKB(KBBase): if not multiple_predictions: if len(pred_res) not in self.len_list: return [], 0, 0 - all_candidates = self.base[len(pred_res)][key] + all_candidates = self._find_candidate_GKB(pred_res, key) if len(all_candidates) == 0: return [], 0, 0 else: @@ -168,7 +92,7 @@ class ClsKB(KBBase): idxs = np.where(cost_list <= address_num)[0] candidates = [all_candidates[idx] for idx in idxs] return candidates, min_address_num, address_num - + else: min_address_num = 0 all_candidates_save = [] @@ -177,7 +101,7 @@ class ClsKB(KBBase): for p_res, k in zip(pred_res, key): if len(p_res) not in self.len_list: return [], 0, 0 - all_candidates = self.base[len(p_res)][k] + all_candidates = self._regression_find_candidate_GKB(p_res, k) if len(all_candidates) == 0: return [], 0, 0 else: @@ -194,7 +118,7 @@ class ClsKB(KBBase): idxs = np.where(multiple_cost_list <= address_num)[0] candidates = [reform_idx(multiple_all_candidates[idx], pred_res) for idx in idxs] return candidates, min_address_num, address_num - + def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): candidates = [] abduce_c = list(product(self.pseudo_label_list, repeat=len(address_idx))) @@ -211,10 +135,71 @@ class ClsKB(KBBase): if multiple_predictions: candidate = reform_idx(candidate, save_pred_res) - if check_equal(self._logic_forward(candidate, multiple_predictions), key): + if check_equal(self._logic_forward(candidate, multiple_predictions), key, self.max_err): candidates.append(candidate) return candidates + def _address(self, address_num, pred_res, key, multiple_predictions): + new_candidates = [] + if not multiple_predictions: + address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) + else: + address_idx_list = list(combinations(list(range(len(flatten(pred_res)))), address_num)) + + for address_idx in address_idx_list: + candidates = self.address_by_idx(pred_res, key, address_idx, multiple_predictions) + new_candidates += candidates + return new_candidates + + def _abduce_by_search(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): + candidates = [] + + for address_num in range(len(flatten(pred_res)) + 1): + if address_num == 0: + if check_equal(self._logic_forward(pred_res, multiple_predictions), key, self.max_err): + candidates.append(pred_res) + else: + new_candidates = self._address(address_num, pred_res, key, multiple_predictions) + candidates += new_candidates + + if len(candidates) > 0: + min_address_num = address_num + break + + if address_num >= max_address_num: + return [], 0, 0 + + for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): + if address_num > max_address_num: + return candidates, min_address_num, address_num - 1 + new_candidates = self._address(address_num, pred_res, key, multiple_predictions) + candidates += new_candidates + + return candidates, min_address_num, address_num + + def _dict_len(self, dic): + if not self.GKB_flag: + return 0 + else: + return sum(len(c) for c in dic.values()) + + def __len__(self): + if not self.GKB_flag: + return 0 + else: + return sum(self._dict_len(v) for v in self.base.values()) + + +class ClsKB(KBBase): + def __init__(self, pseudo_label_list, len_list, GKB_flag): + super().__init__(pseudo_label_list, len_list, GKB_flag) + + def logic_forward(self): + pass + + def _find_candidate_GKB(self, pred_res, key): + return self.base[len(pred_res)][key] + class add_KB(ClsKB): def __init__(self, pseudo_label_list=list(range(10)), len_list=[2], GKB_flag=False): @@ -232,16 +217,13 @@ class prolog_KB(KBBase): def logic_forward(self): pass - def abduce_candidates(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): - return self._abduce_by_search(pred_res, key, max_address_num, require_more_address, multiple_predictions) - + def _find_candidate_GKB(self): + pass + def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): candidates = [] # print(address_idx) - if not multiple_predictions: - query_string = self.get_query_string(pred_res, key, address_idx) - else: - query_string = self.get_query_string_need_flatten(pred_res, key, address_idx) + query_string = self.get_query_string(pred_res, key, address_idx) if multiple_predictions: save_pred_res = pred_res @@ -284,21 +266,18 @@ class HED_prolog_KB(prolog_KB): super().__init__(pseudo_label_list) self.prolog.consult('./datasets/hed/learn_add.pl') - # corresponding to `con_sol is not None` in `consistent_score_mapped` within `learn_add.py` def logic_forward(self, exs): return len(list(self.prolog.query("abduce_consistent_insts([%s])." % exs))) != 0 - def get_query_string_need_flatten(self, pred_res, key, address_idx): - # flatten + def get_query_string(self, pred_res, key, address_idx): flatten_pred_res = flatten(pred_res) # add variables for prolog for idx in range(len(flatten_pred_res)): if idx in address_idx: flatten_pred_res[idx] = 'X' + str(idx) - # unflatten - new_pred_res = reform_idx(flatten_pred_res, pred_res) + pred_res = reform_idx(flatten_pred_res, pred_res) - query_string = "abduce_consistent_insts(%s)." % new_pred_res + query_string = "abduce_consistent_insts(%s)." % pred_res return query_string.replace("'", "").replace("+", "'+'").replace("=", "'='") def consist_rule(self, exs, rules): @@ -324,13 +303,7 @@ class RegKB(KBBase): def logic_forward(self): pass - def abduce_candidates(self, pred_res, key, max_address_num=-1, require_more_address=0, multiple_predictions=False): - if self.GKB_flag: - return self._abduce_by_GKB(pred_res, key, max_address_num, require_more_address, multiple_predictions) - else: - return self._abduce_by_search(pred_res, key, max_address_num, require_more_address, multiple_predictions) - - def _regression_find_candidate_GKB(self, pred_res, key): + def _find_candidate_GKB(self, pred_res, key): potential_candidates = self.base[len(pred_res)] key_list = sorted(potential_candidates) key_idx = bisect.bisect_left(key_list, key) @@ -351,70 +324,6 @@ class RegKB(KBBase): break return all_candidates - def _abduce_by_GKB(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): - if self.base == {}: - return [], 0, 0 - - if not multiple_predictions: - if len(pred_res) not in self.len_list: - return [], 0, 0 - all_candidates = self._regression_find_candidate_GKB(pred_res, key) - if len(all_candidates) == 0: - return [], 0, 0 - else: - cost_list = hamming_dist(pred_res, all_candidates) - min_address_num = np.min(cost_list) - address_num = min(max_address_num, min_address_num + require_more_address) - idxs = np.where(cost_list <= address_num)[0] - candidates = [all_candidates[idx] for idx in idxs] - return candidates, min_address_num, address_num - - else: - min_address_num = 0 - all_candidates_save = [] - cost_list_save = [] - - for p_res, k in zip(pred_res, key): - if len(p_res) not in self.len_list: - return [], 0, 0 - all_candidates = self._regression_find_candidate_GKB(p_res, k) - if len(all_candidates) == 0: - return [], 0, 0 - else: - all_candidates_save.append(all_candidates) - cost_list = hamming_dist(p_res, all_candidates) - min_address_num += np.min(cost_list) - cost_list_save.append(cost_list) - - multiple_all_candidates = [flatten(c) for c in product(*all_candidates_save)] - assert len(multiple_all_candidates[0]) == len(flatten(pred_res)) - multiple_cost_list = np.array([sum(cost) for cost in product(*cost_list_save)]) - assert len(multiple_all_candidates) == len(multiple_cost_list) - address_num = min(max_address_num, min_address_num + require_more_address) - idxs = np.where(multiple_cost_list <= address_num)[0] - candidates = [reform_idx(multiple_all_candidates[idx], pred_res) for idx in idxs] - return candidates, min_address_num, address_num - - def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): - candidates = [] - abduce_c = list(product(self.pseudo_label_list, repeat=len(address_idx))) - - if multiple_predictions: - save_pred_res = pred_res - pred_res = flatten(pred_res) - - for c in abduce_c: - candidate = pred_res.copy() - for i, idx in enumerate(address_idx): - candidate[idx] = c[i] - - if multiple_predictions: - candidate = reform_idx(candidate, save_pred_res) - - if check_equal(self._logic_forward(candidate, multiple_predictions), key, self.max_err): - candidates.append(candidate) - return candidates - class HWF_KB(RegKB): def __init__( @@ -456,13 +365,6 @@ class HWF_KB(RegKB): formula = [mapping[f] for f in formula] return round(eval(''.join(formula)), 2) - -import time - if __name__ == "__main__": - t1 = time.time() - kb = add_KB(GKB_flag=True) - t2 = time.time() - print(t2 - t1) - + pass From 9d9684723846c3e63af3913e78ee45d39e474665 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 3 Mar 2023 18:42:19 +0800 Subject: [PATCH 162/601] Rearrange abduce_by_GKB and address_by_idx to Base --- abl/abducer/kb.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 7c494c5..8db7bba 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -10,6 +10,19 @@ # # ================================================================# +from abc import ABC, abstractmethod +import bisect +import copy +import numpy as np + +from collections import defaultdict +from itertools import product, combinations +from ..utils.utils import flatten, reform_idx, hamming_dist, check_equal + +from multiprocessing import Pool + +import pyswip + class KBBase(ABC): def __init__(self, pseudo_label_list=None, len_list=None, GKB_flag=False, max_err=0): self.pseudo_label_list = pseudo_label_list From 1d1873b6eba87726043838ed69cad12f997a64a6 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 3 Mar 2023 18:56:24 +0800 Subject: [PATCH 163/601] Rearrange sorted in RegKB --- abl/abducer/kb.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 8db7bba..137647b 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -63,6 +63,9 @@ class KBBase(ABC): part_X, part_Y = zip(*XY_list) X.extend(part_X) Y.extend(part_Y) + sorted_XY = sorted(list(zip(Y, X))) + X = [x for y, x in sorted_XY] + Y = [y for y, x in sorted_XY] return X, Y @abstractmethod @@ -318,7 +321,7 @@ class RegKB(KBBase): def _find_candidate_GKB(self, pred_res, key): potential_candidates = self.base[len(pred_res)] - key_list = sorted(potential_candidates) + key_list = list(potential_candidates.keys()) key_idx = bisect.bisect_left(key_list, key) all_candidates = [] @@ -378,6 +381,9 @@ class HWF_KB(RegKB): formula = [mapping[f] for f in formula] return round(eval(''.join(formula)), 2) + +import time + if __name__ == "__main__": pass From ce406011bf538f0ec5567f360a9079113c192fe1 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 3 Mar 2023 18:59:18 +0800 Subject: [PATCH 164/601] Rearrange sorted in RegKB --- abl/abducer/kb.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 137647b..3be0875 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -63,9 +63,10 @@ class KBBase(ABC): part_X, part_Y = zip(*XY_list) X.extend(part_X) Y.extend(part_Y) - sorted_XY = sorted(list(zip(Y, X))) - X = [x for y, x in sorted_XY] - Y = [y for y, x in sorted_XY] + if self.max_err != 0: + sorted_XY = sorted(list(zip(Y, X))) + X = [x for y, x in sorted_XY] + Y = [y for y, x in sorted_XY] return X, Y @abstractmethod From 253c9e20ba5b1fa75815405439513d5976bd66a3 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 3 Mar 2023 19:08:21 +0800 Subject: [PATCH 165/601] Update kb.py --- abl/abducer/kb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 3be0875..7eee9f5 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -118,7 +118,7 @@ class KBBase(ABC): for p_res, k in zip(pred_res, key): if len(p_res) not in self.len_list: return [], 0, 0 - all_candidates = self._regression_find_candidate_GKB(p_res, k) + all_candidates = self._find_candidate_GKB(p_res, k) if len(all_candidates) == 0: return [], 0, 0 else: From 1cd3570693f18225f80566af925e14dd5be40b27 Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Fri, 3 Mar 2023 20:02:15 +0800 Subject: [PATCH 166/601] make code short --- abl/abducer/kb.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 3be0875..627d6c8 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -77,9 +77,7 @@ class KBBase(ABC): if not multiple_predictions: return self.logic_forward(xs) else: - res = [] - for x in xs: - res.append(self.logic_forward(x)) + res = [self.logic_forward(x) for x in xs] return res def abduce_candidates(self, pred_res, key, max_address_num=-1, require_more_address=0, multiple_predictions=False): From ea66df54fbf5a1987c1c76c8edbc7e5ab336e40d Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Fri, 3 Mar 2023 20:04:19 +0800 Subject: [PATCH 167/601] remove round in reg --- abl/abducer/kb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 4178c4e..0cff3fa 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -378,7 +378,7 @@ class HWF_KB(RegKB): 'div': '/', } formula = [mapping[f] for f in formula] - return round(eval(''.join(formula)), 2) + return eval(''.join(formula)) import time From 53586d94f862c86ed0c9bec494801f410fc472fd Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Fri, 3 Mar 2023 21:53:06 +0800 Subject: [PATCH 168/601] Create add.pl --- examples/datasets/mnist_add/add.pl | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 examples/datasets/mnist_add/add.pl diff --git a/examples/datasets/mnist_add/add.pl b/examples/datasets/mnist_add/add.pl new file mode 100644 index 0000000..96f0869 --- /dev/null +++ b/examples/datasets/mnist_add/add.pl @@ -0,0 +1,2 @@ +pseudo_label(N) :- between(0, 9, N). +logic_forward([Z1, Z2], Res) :- pseudo_label(Z1), pseudo_label(Z2), Res is Z1+Z2. From 8ba7c509e80c2cc7c01914a53d832ae8d13360dc Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 6 Mar 2023 05:27:41 +0000 Subject: [PATCH 169/601] Update prologKB --- abl/abducer/abducer_base.py | 13 +++--- abl/abducer/kb.py | 63 ++++++++++++++---------------- abl/framework_hed.py | 4 +- examples/datasets/hed/learn_add.pl | 3 ++ 4 files changed, 42 insertions(+), 41 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index 9fcfa0a..777533a 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -163,7 +163,7 @@ if __name__ == '__main__': prob1 = [[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] prob2 = [[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] - kb = add_KB(True) + kb = add_KB(GKB_flag=True) abd = AbducerBase(kb, 'confidence') res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) print(res) @@ -219,14 +219,15 @@ if __name__ == '__main__': print(res) print() - kb = HWF_KB(True, len_list=[1, 3, 5], max_err = 0.1) + kb = HWF_KB(GKB_flag=True, len_list=[1, 3, 5], max_err = 0.1) abd = AbducerBase(kb, 'hamming') res = abd.abduce((['5', '+', '2'], None, 3), max_address_num=2, require_more_address=0) print(res) res = abd.abduce((['5', '+', '9'], None, 64), max_address_num=3, require_more_address=0) print(res) + print() - kb = HWF_KB(True, len_list=[1, 3, 5], max_err = 1) + kb = HWF_KB(GKB_flag=True, len_list=[1, 3, 5], max_err = 1) abd = AbducerBase(kb, 'hamming') res = abd.abduce((['5', '+', '9'], None, 64), max_address_num=3, require_more_address=0) print(res) @@ -270,11 +271,11 @@ if __name__ == '__main__': print(kb.consist_rule([1, '+', 1, '=', 1, 0], rules), kb.consist_rule([1, '+', 1, '=', 1, 1], rules)) print() - res = abd.abduce((consist_exs, None, [1] * len(consist_exs))) + res = abd.abduce((consist_exs, None, [None] * len(consist_exs))) print(res) - res = abd.abduce((inconsist_exs, None, [1] * len(consist_exs))) + res = abd.abduce((inconsist_exs, None, [None] * len(inconsist_exs))) print(res) print() abduced_rules = abd.abduce_rules(consist_exs) - print(abduced_rules) + print(abduced_rules) \ No newline at end of file diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 0cff3fa..e23e637 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -229,30 +229,52 @@ class prolog_KB(KBBase): super().__init__(pseudo_label_list) self.prolog = pyswip.Prolog() - def logic_forward(self): - pass + def logic_forward(self, pseudo_labels): + result = list(self.prolog.query("logic_forward(%s, Res)." % pseudo_labels))[0]['Res'] + if result == 'true': + return True + elif result == 'false': + return False + return result + + def _address_pred_res(self, pred_res, address_idx, multiple_predictions): + import re + address_pred_res = pred_res.copy() + if multiple_predictions: + address_pred_res = flatten(address_pred_res) + + for idx in range(len(address_pred_res)): + if idx in address_idx: + address_pred_res[idx] = 'P' + str(idx) + if multiple_predictions: + address_pred_res = reform_idx(address_pred_res, pred_res) + + regex = r"'P\d+'" + return re.sub(regex, lambda x: x.group().replace("'", ""), str(address_pred_res)) + + def get_query_string(self, pred_res, key, address_idx, multiple_predictions): + query_string = "logic_forward(" + query_string += self._address_pred_res(pred_res, address_idx, multiple_predictions) + key_is_none_flag = key is None or (type(key) == list and key[0] is None) + query_string += ",%s)." % key if not key_is_none_flag else ")." + return query_string def _find_candidate_GKB(self): pass def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): candidates = [] - # print(address_idx) - query_string = self.get_query_string(pred_res, key, address_idx) - + query_string = self.get_query_string(pred_res, key, address_idx, multiple_predictions) if multiple_predictions: save_pred_res = pred_res pred_res = flatten(pred_res) - abduce_c = [list(z.values()) for z in list(self.prolog.query(query_string))] for c in abduce_c: candidate = pred_res.copy() for i, idx in enumerate(address_idx): candidate[idx] = c[i] - if multiple_predictions: candidate = reform_idx(candidate, save_pred_res) - candidates.append(candidate) return candidates @@ -264,37 +286,12 @@ class add_prolog_KB(prolog_KB): self.prolog.assertz("pseudo_label(%s)" % i) self.prolog.assertz("addition(Z1, Z2, Res) :- pseudo_label(Z1), pseudo_label(Z2), Res is Z1+Z2") - def logic_forward(self, nums): - return list(self.prolog.query("addition(%s, %s, Res)." % (nums[0], nums[1])))[0]['Res'] - - def get_query_string(self, pred_res, key, address_idx): - query_string = "addition(" - for idx, i in enumerate(pred_res): - tmp = 'Z' + str(idx) + ',' if idx in address_idx else str(i) + ',' - query_string += tmp - query_string += "%s)." % key - return query_string - class HED_prolog_KB(prolog_KB): def __init__(self, pseudo_label_list=[0, 1, '+', '=']): super().__init__(pseudo_label_list) self.prolog.consult('./datasets/hed/learn_add.pl') - def logic_forward(self, exs): - return len(list(self.prolog.query("abduce_consistent_insts([%s])." % exs))) != 0 - - def get_query_string(self, pred_res, key, address_idx): - flatten_pred_res = flatten(pred_res) - # add variables for prolog - for idx in range(len(flatten_pred_res)): - if idx in address_idx: - flatten_pred_res[idx] = 'X' + str(idx) - pred_res = reform_idx(flatten_pred_res, pred_res) - - query_string = "abduce_consistent_insts(%s)." % pred_res - return query_string.replace("'", "").replace("+", "'+'").replace("=", "'='") - def consist_rule(self, exs, rules): rules = str(rules).replace("\'","") return len(list(self.prolog.query("eval_inst_feature(%s, %s)." % (exs, rules)))) != 0 diff --git a/abl/framework_hed.py b/abl/framework_hed.py index d942be6..171c247 100644 --- a/abl/framework_hed.py +++ b/abl/framework_hed.py @@ -150,7 +150,7 @@ def abduce_and_train(model, abducer, mapping, train_X_true, select_num): for m in mappings: pred_res = mapping_res(original_pred_res, m) max_abduce_num = 20 - solution = abducer.zoopt_get_solution(pred_res, [1] * len(pred_res), max_abduce_num) + solution = abducer.zoopt_get_solution(pred_res, [None] * len(pred_res), max_abduce_num) all_address_flag = reform_idx(solution, pred_res) consistent_idx_tmp = [] @@ -158,7 +158,7 @@ def abduce_and_train(model, abducer, mapping, train_X_true, select_num): for idx in range(len(pred_res)): address_idx = [i for i, flag in enumerate(all_address_flag[idx]) if flag != 0] - candidate = abducer.kb.address_by_idx([pred_res[idx]], 1, address_idx, True) + candidate = abducer.kb.address_by_idx([pred_res[idx]], None, address_idx, True) if len(candidate) > 0: consistent_idx_tmp.append(idx) consistent_pred_res_tmp.append(candidate[0][0]) diff --git a/examples/datasets/hed/learn_add.pl b/examples/datasets/hed/learn_add.pl index af1d6bb..fbf698f 100644 --- a/examples/datasets/hed/learn_add.pl +++ b/examples/datasets/hed/learn_add.pl @@ -32,6 +32,9 @@ abduce_consistent_insts(Exs):- % (Experimental) Uncomment to use parallel abduction % abduce_consistent_exs_concurrent(Exs), !. +logic_forward(Exs, X) :- abduce_consistent_insts([Exs]) -> X = true ; X = false. +logic_forward(Exs) :- abduce_consistent_insts(Exs). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Abduce Delta_C given pseudo-labels %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% From 3c736686d1a65d7a0d339c907547e6ebf224255b Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 6 Mar 2023 13:31:04 +0800 Subject: [PATCH 170/601] Change the sorting condition in _get_GKB --- abl/abducer/kb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index e23e637..7aff683 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -63,7 +63,7 @@ class KBBase(ABC): part_X, part_Y = zip(*XY_list) X.extend(part_X) Y.extend(part_Y) - if self.max_err != 0: + if type(Y[0]) in (int, float): sorted_XY = sorted(list(zip(Y, X))) X = [x for y, x in sorted_XY] Y = [y for y, x in sorted_XY] From 2160df0bb79ccc20f2f484bc1a29af07105fc3d3 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 6 Mar 2023 13:57:17 +0800 Subject: [PATCH 171/601] Update kb.py --- abl/abducer/kb.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 7aff683..71bdcbe 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -282,9 +282,7 @@ class prolog_KB(KBBase): class add_prolog_KB(prolog_KB): def __init__(self, pseudo_label_list=list(range(10))): super().__init__(pseudo_label_list) - for i in self.pseudo_label_list: - self.prolog.assertz("pseudo_label(%s)" % i) - self.prolog.assertz("addition(Z1, Z2, Res) :- pseudo_label(Z1), pseudo_label(Z2), Res is Z1+Z2") + self.prolog.consult('../datasets/mnist_add/add.pl') class HED_prolog_KB(prolog_KB): From 52f8451d56475b5ac0a30786b4d56c788679a561 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 6 Mar 2023 08:02:17 +0000 Subject: [PATCH 172/601] Update prolog_KB --- abl/abducer/abducer_base.py | 8 ++++---- abl/abducer/kb.py | 15 ++------------- examples/example.py | 4 ++-- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index 777533a..cb50ee3 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -158,7 +158,7 @@ class AbducerBase(abc.ABC): if __name__ == '__main__': - from kb import add_KB, add_prolog_KB, HWF_KB, HED_prolog_KB + from kb import add_KB, prolog_KB, HWF_KB prob1 = [[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] prob2 = [[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] @@ -191,7 +191,7 @@ if __name__ == '__main__': print() - kb = add_prolog_KB() + kb = prolog_KB(pseudo_label_list=list(range(10)), pl_file='../examples/datasets/mnist_add/add.pl') abd = AbducerBase(kb, 'confidence') res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) print(res) @@ -205,7 +205,7 @@ if __name__ == '__main__': print(res) print() - kb = add_prolog_KB() + kb = prolog_KB(pseudo_label_list=list(range(10)), pl_file='../examples/datasets/mnist_add/add.pl') abd = AbducerBase(kb, 'confidence', zoopt=True) res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) print(res) @@ -260,7 +260,7 @@ if __name__ == '__main__': print(res) print() - kb = HED_prolog_KB() + kb = prolog_KB(pseudo_label_list=[1, 0, '+', '='], pl_file='../examples/datasets/hed/hed.pl') abd = AbducerBase(kb, zoopt=True, multiple_predictions=True) consist_exs = [[1, 1, '+', 0, '=', 1, 1], [1, '+', 1, '=', 1, 0], [0, '+', 0, '=', 0]] inconsist_exs = [[1, '+', 0, '=', 0], [1, '=', 1, '=', 0], [0, '=', 0, '=', 1, 1]] diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 71bdcbe..c5fc675 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -225,9 +225,10 @@ class add_KB(ClsKB): class prolog_KB(KBBase): - def __init__(self, pseudo_label_list): + def __init__(self, pseudo_label_list, pl_file): super().__init__(pseudo_label_list) self.prolog = pyswip.Prolog() + self.prolog.consult(pl_file) def logic_forward(self, pseudo_labels): result = list(self.prolog.query("logic_forward(%s, Res)." % pseudo_labels))[0]['Res'] @@ -278,18 +279,6 @@ class prolog_KB(KBBase): candidates.append(candidate) return candidates - -class add_prolog_KB(prolog_KB): - def __init__(self, pseudo_label_list=list(range(10))): - super().__init__(pseudo_label_list) - self.prolog.consult('../datasets/mnist_add/add.pl') - - -class HED_prolog_KB(prolog_KB): - def __init__(self, pseudo_label_list=[0, 1, '+', '=']): - super().__init__(pseudo_label_list) - self.prolog.consult('./datasets/hed/learn_add.pl') - def consist_rule(self, exs, rules): rules = str(rules).replace("\'","") return len(list(self.prolog.query("eval_inst_feature(%s, %s)." % (exs, rules)))) != 0 diff --git a/examples/example.py b/examples/example.py index 30c50fc..ee0b898 100644 --- a/examples/example.py +++ b/examples/example.py @@ -20,7 +20,7 @@ from models.wabl_models import DecisionTree, WABLBasicModel from multiprocessing import Pool from abducer.abducer_base import AbducerBase -from abducer.kb import add_KB, HWF_KB, HED_prolog_KB +from abducer.kb import add_KB, HWF_KB, prolog_KB from datasets.mnist_add.get_mnist_add import get_mnist_add from datasets.hwf.get_hwf import get_hwf from datasets.hed.get_hed import get_hed, split_equation @@ -33,7 +33,7 @@ def run_test(): # kb = HWF_KB(True) # abducer = AbducerBase(kb) - kb = HED_prolog_KB() + kb = prolog_KB(pseudo_label_list=[1, 0, '+', '='], pl_file='../examples/datasets/hed/hed.pl') abducer = AbducerBase(kb, zoopt=True, multiple_predictions=True) recorder = logger() From 42a43b3cca4d5ebf85efcdb02990de136a58ce86 Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Mon, 6 Mar 2023 16:24:28 +0800 Subject: [PATCH 173/601] update para of method --- abl/abducer/kb.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index c5fc675..632bd42 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -24,6 +24,7 @@ from multiprocessing import Pool import pyswip class KBBase(ABC): + # TODO:有些ä¸èƒ½æ˜¯é»˜è®¤å‚数,必须给定 def __init__(self, pseudo_label_list=None, len_list=None, GKB_flag=False, max_err=0): self.pseudo_label_list = pseudo_label_list self.len_list = len_list @@ -70,7 +71,7 @@ class KBBase(ABC): return X, Y @abstractmethod - def logic_forward(self): + def logic_forward(self, pseudo_labels): pass def _logic_forward(self, xs, multiple_predictions=False): @@ -87,7 +88,7 @@ class KBBase(ABC): return self._abduce_by_search(pred_res, key, max_address_num, require_more_address, multiple_predictions) @abstractmethod - def _find_candidate_GKB(self): + def _find_candidate_GKB(self, pred_res, key): pass def _abduce_by_GKB(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): @@ -260,7 +261,7 @@ class prolog_KB(KBBase): query_string += ",%s)." % key if not key_is_none_flag else ")." return query_string - def _find_candidate_GKB(self): + def _find_candidate_GKB(self, pred_res, key): pass def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): From 4e909320037df506320b74b54f11605eecadb9ac Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Mon, 6 Mar 2023 16:39:12 +0800 Subject: [PATCH 174/601] update package for example.py --- examples/example.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/examples/example.py b/examples/example.py index ee0b898..a6a5194 100644 --- a/examples/example.py +++ b/examples/example.py @@ -10,21 +10,24 @@ # # ================================================================# -from utils.plog import logger, INFO +import sys +sys.path.append("../") + +from abl.utils.plog import logger, INFO import torch.nn as nn import torch -from models.nn import LeNet5, SymbolNet -from models.basic_model import BasicModel, BasicDataset -from models.wabl_models import DecisionTree, WABLBasicModel +from abl.models.nn import LeNet5, SymbolNet +from abl.models.basic_model import BasicModel, BasicDataset +from abl.models.wabl_models import DecisionTree, WABLBasicModel from multiprocessing import Pool -from abducer.abducer_base import AbducerBase -from abducer.kb import add_KB, HWF_KB, prolog_KB +from abl.abducer.abducer_base import AbducerBase +from abl.abducer.kb import add_KB, HWF_KB, prolog_KB from datasets.mnist_add.get_mnist_add import get_mnist_add from datasets.hwf.get_hwf import get_hwf from datasets.hed.get_hed import get_hed, split_equation -import framework_hed +from abl import framework_hed def run_test(): From c98e516e43898b0c431c339f62009aa8a63bb701 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 6 Mar 2023 08:47:45 +0000 Subject: [PATCH 175/601] change pl_file name for HED --- abl/abducer/abducer_base.py | 2 +- abl/abducer/kb.py | 3 +-- examples/example.py | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index cb50ee3..712eb46 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -260,7 +260,7 @@ if __name__ == '__main__': print(res) print() - kb = prolog_KB(pseudo_label_list=[1, 0, '+', '='], pl_file='../examples/datasets/hed/hed.pl') + kb = prolog_KB(pseudo_label_list=[1, 0, '+', '='], pl_file='../examples/datasets/hed/learn_add.pl') abd = AbducerBase(kb, zoopt=True, multiple_predictions=True) consist_exs = [[1, 1, '+', 0, '=', 1, 1], [1, '+', 1, '=', 1, 0], [0, '+', 0, '=', 0]] inconsist_exs = [[1, '+', 0, '=', 0], [1, '=', 1, '=', 0], [0, '=', 0, '=', 1, 1]] diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 632bd42..d937dcf 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -24,8 +24,7 @@ from multiprocessing import Pool import pyswip class KBBase(ABC): - # TODO:有些ä¸èƒ½æ˜¯é»˜è®¤å‚数,必须给定 - def __init__(self, pseudo_label_list=None, len_list=None, GKB_flag=False, max_err=0): + def __init__(self, pseudo_label_list, len_list=None, GKB_flag=False, max_err=0): self.pseudo_label_list = pseudo_label_list self.len_list = len_list self.GKB_flag = GKB_flag diff --git a/examples/example.py b/examples/example.py index a6a5194..c74f1b3 100644 --- a/examples/example.py +++ b/examples/example.py @@ -36,7 +36,7 @@ def run_test(): # kb = HWF_KB(True) # abducer = AbducerBase(kb) - kb = prolog_KB(pseudo_label_list=[1, 0, '+', '='], pl_file='../examples/datasets/hed/hed.pl') + kb = prolog_KB(pseudo_label_list=[1, 0, '+', '='], pl_file='../examples/datasets/hed/learn_add.pl') abducer = AbducerBase(kb, zoopt=True, multiple_predictions=True) recorder = logger() From fe52f91385c17ba639f3a9f7635d6f78825f7e4c Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Mon, 6 Mar 2023 19:39:59 +0800 Subject: [PATCH 176/601] speed up --- abl/utils/utils.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/abl/utils/utils.py b/abl/utils/utils.py index fbb5bfb..acc7f94 100644 --- a/abl/utils/utils.py +++ b/abl/utils/utils.py @@ -7,6 +7,7 @@ def flatten(l): # return [item for sublist in l for item in flatten(sublist)] if isinstance(l, (list, tuple)) else [l] if not isinstance(l[0], (list, tuple)): return l + # TODO ç¨å¾®å¯¹æ¯”一下和itertools.chain.from_iterable(nested_list)的速度区别,看看哪个好 return [item for sublist in l for item in sublist] if isinstance(l, (list, tuple)) else [l] # for multiple predictions, modify from `learn_add.py` @@ -14,13 +15,8 @@ def reform_idx(flatten_pred_res, save_pred_res): re = [] i = 0 for e in save_pred_res: - j = 0 - idx = [] - while j < len(e): - idx.append(flatten_pred_res[i + j]) - j += 1 - re.append(idx) - i = i + j + re.append(flatten_pred_res[i:i + len(e)]) + i += len(e) return re def hamming_dist(A, B): From e436421fb52e3d6502f630aff25c8e704397030f Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 6 Mar 2023 20:09:11 +0800 Subject: [PATCH 177/601] Update framework_hed.py --- abl/framework_hed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abl/framework_hed.py b/abl/framework_hed.py index 171c247..a823b13 100644 --- a/abl/framework_hed.py +++ b/abl/framework_hed.py @@ -214,7 +214,7 @@ def get_rules_from_data(model, abducer, mapping, train_X_true, samples_per_rule, consistent_idx = [] consistent_pred_res = [] for idx in range(len(pred_res)): - if abducer.kb.logic_forward([pred_res[idx]]): + if abducer.kb.logic_forward(pred_res[idx]): consistent_idx.append(idx) consistent_pred_res.append(pred_res[idx]) From bfd6dc8a5c37c680c683a3c3d9c4efe756853248 Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Tue, 7 Mar 2023 00:01:08 +0800 Subject: [PATCH 178/601] update TODO in kb.py --- abl/abducer/kb.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index d937dcf..9ae919a 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -80,6 +80,7 @@ class KBBase(ABC): res = [self.logic_forward(x) for x in xs] return res + # TODO:这里max_address_num默认值-1,åŽé¢è¿è¡Œä¼šæœ‰é—®é¢˜å— def abduce_candidates(self, pred_res, key, max_address_num=-1, require_more_address=0, multiple_predictions=False): if self.GKB_flag: return self._abduce_by_GKB(pred_res, key, max_address_num, require_more_address, multiple_predictions) @@ -134,8 +135,10 @@ class KBBase(ABC): candidates = [reform_idx(multiple_all_candidates[idx], pred_res) for idx in idxs] return candidates, min_address_num, address_num + # TODO:应该也是内部使用的方法? def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): candidates = [] + # TODO:product combinations本身就是迭代器,如果没有其他用途,ä¸ç”¨è½¬list,直接放到循环那å³å¯ï¼ŒçœåŽ»ä¸€äº›æ—¶é—´ï¼Œä¸‹é¢çš„åŒç† abduce_c = list(product(self.pseudo_label_list, repeat=len(address_idx))) if multiple_predictions: @@ -209,7 +212,8 @@ class ClsKB(KBBase): def __init__(self, pseudo_label_list, len_list, GKB_flag): super().__init__(pseudo_label_list, len_list, GKB_flag) - def logic_forward(self): + # TODO:这里以åŠRegKBå¯ä»¥ä¸å®žçްlogic_forwardå—,这样用户继承åŽä¸å®žçްlogic_forward就会报错 + def logic_forward(self, pseudo_labels): pass def _find_candidate_GKB(self, pred_res, key): @@ -243,13 +247,15 @@ class prolog_KB(KBBase): address_pred_res = pred_res.copy() if multiple_predictions: address_pred_res = flatten(address_pred_res) - + + # TODO:å¯ä»¥ç›´æŽ¥å¯¹address_idx循环? for idx in range(len(address_pred_res)): if idx in address_idx: address_pred_res[idx] = 'P' + str(idx) if multiple_predictions: address_pred_res = reform_idx(address_pred_res, pred_res) + # TODO:ä¸çŸ¥é“有没有更简æ´çš„æ–¹æ³• regex = r"'P\d+'" return re.sub(regex, lambda x: x.group().replace("'", ""), str(address_pred_res)) @@ -269,6 +275,7 @@ class prolog_KB(KBBase): if multiple_predictions: save_pred_res = pred_res pred_res = flatten(pred_res) + # TODO:这里åŽé¢çš„那个list应该也ä¸éœ€è¦ abduce_c = [list(z.values()) for z in list(self.prolog.query(query_string))] for c in abduce_c: candidate = pred_res.copy() @@ -289,17 +296,15 @@ class prolog_KB(KBBase): if len(prolog_result) == 0: return None prolog_rules = prolog_result[0]['X'] - rules = [] - for rule in prolog_rules: - rules.append(rule.value) + rules = [rule.value for rule in prolog_rules] return rules - +# TODO:和ClsKBçš„å‚æ•°é¡ºåºä¸ç»Ÿä¸€ class RegKB(KBBase): def __init__(self, GKB_flag=False, pseudo_label_list=None, len_list=None, max_err=1e-3): super().__init__(pseudo_label_list, len_list, GKB_flag, max_err) - def logic_forward(self): + def logic_forward(self, pseudo_labels): pass def _find_candidate_GKB(self, pred_res, key): @@ -333,6 +338,7 @@ class HWF_KB(RegKB): ): super().__init__(GKB_flag, pseudo_label_list, len_list, max_err) + # TODOï¼šåº”è¯¥æ˜¯é™æ€æ–¹æ³• def valid_candidate(self, formula): if len(formula) % 2 == 0: return False From e911ef1103d74cc05b2bd9e3c973764b3c707111 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 7 Mar 2023 00:17:55 +0000 Subject: [PATCH 179/601] Update several files --- abl/abducer/abducer_base.py | 4 ++-- abl/abducer/kb.py | 44 +++++++++++++------------------------ abl/utils/utils.py | 9 ++++---- 3 files changed, 21 insertions(+), 36 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index 712eb46..bd76831 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -219,7 +219,7 @@ if __name__ == '__main__': print(res) print() - kb = HWF_KB(GKB_flag=True, len_list=[1, 3, 5], max_err = 0.1) + kb = HWF_KB(len_list=[1, 3, 5], GKB_flag=True, max_err = 0.1) abd = AbducerBase(kb, 'hamming') res = abd.abduce((['5', '+', '2'], None, 3), max_address_num=2, require_more_address=0) print(res) @@ -227,7 +227,7 @@ if __name__ == '__main__': print(res) print() - kb = HWF_KB(GKB_flag=True, len_list=[1, 3, 5], max_err = 1) + kb = HWF_KB(len_list=[1, 3, 5], GKB_flag=True, max_err = 1) abd = AbducerBase(kb, 'hamming') res = abd.abduce((['5', '+', '9'], None, 64), max_address_num=3, require_more_address=0) print(res) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 9ae919a..5b82f03 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -80,8 +80,7 @@ class KBBase(ABC): res = [self.logic_forward(x) for x in xs] return res - # TODO:这里max_address_num默认值-1,åŽé¢è¿è¡Œä¼šæœ‰é—®é¢˜å— - def abduce_candidates(self, pred_res, key, max_address_num=-1, require_more_address=0, multiple_predictions=False): + def abduce_candidates(self, pred_res, key, max_address_num, require_more_address=0, multiple_predictions=False): if self.GKB_flag: return self._abduce_by_GKB(pred_res, key, max_address_num, require_more_address, multiple_predictions) else: @@ -135,11 +134,9 @@ class KBBase(ABC): candidates = [reform_idx(multiple_all_candidates[idx], pred_res) for idx in idxs] return candidates, min_address_num, address_num - # TODO:应该也是内部使用的方法? def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): candidates = [] - # TODO:product combinations本身就是迭代器,如果没有其他用途,ä¸ç”¨è½¬list,直接放到循环那å³å¯ï¼ŒçœåŽ»ä¸€äº›æ—¶é—´ï¼Œä¸‹é¢çš„åŒç† - abduce_c = list(product(self.pseudo_label_list, repeat=len(address_idx))) + abduce_c = product(self.pseudo_label_list, repeat=len(address_idx)) if multiple_predictions: save_pred_res = pred_res @@ -160,9 +157,9 @@ class KBBase(ABC): def _address(self, address_num, pred_res, key, multiple_predictions): new_candidates = [] if not multiple_predictions: - address_idx_list = list(combinations(list(range(len(pred_res))), address_num)) + address_idx_list = combinations(list(range(len(pred_res))), address_num) else: - address_idx_list = list(combinations(list(range(len(flatten(pred_res)))), address_num)) + address_idx_list = combinations(list(range(len(flatten(pred_res)))), address_num) for address_idx in address_idx_list: candidates = self.address_by_idx(pred_res, key, address_idx, multiple_predictions) @@ -212,10 +209,6 @@ class ClsKB(KBBase): def __init__(self, pseudo_label_list, len_list, GKB_flag): super().__init__(pseudo_label_list, len_list, GKB_flag) - # TODO:这里以åŠRegKBå¯ä»¥ä¸å®žçްlogic_forwardå—,这样用户继承åŽä¸å®žçްlogic_forward就会报错 - def logic_forward(self, pseudo_labels): - pass - def _find_candidate_GKB(self, pred_res, key): return self.base[len(pred_res)][key] @@ -248,10 +241,8 @@ class prolog_KB(KBBase): if multiple_predictions: address_pred_res = flatten(address_pred_res) - # TODO:å¯ä»¥ç›´æŽ¥å¯¹address_idx循环? - for idx in range(len(address_pred_res)): - if idx in address_idx: - address_pred_res[idx] = 'P' + str(idx) + for idx in address_idx: + address_pred_res[idx] = 'P' + str(idx) if multiple_predictions: address_pred_res = reform_idx(address_pred_res, pred_res) @@ -275,8 +266,7 @@ class prolog_KB(KBBase): if multiple_predictions: save_pred_res = pred_res pred_res = flatten(pred_res) - # TODO:这里åŽé¢çš„那个list应该也ä¸éœ€è¦ - abduce_c = [list(z.values()) for z in list(self.prolog.query(query_string))] + abduce_c = [list(z.values()) for z in self.prolog.query(query_string)] for c in abduce_c: candidate = pred_res.copy() for i, idx in enumerate(address_idx): @@ -299,14 +289,11 @@ class prolog_KB(KBBase): rules = [rule.value for rule in prolog_rules] return rules -# TODO:和ClsKBçš„å‚æ•°é¡ºåºä¸ç»Ÿä¸€ + class RegKB(KBBase): - def __init__(self, GKB_flag=False, pseudo_label_list=None, len_list=None, max_err=1e-3): + def __init__(self, pseudo_label_list=None, len_list=None, GKB_flag=False, max_err=1e-3): super().__init__(pseudo_label_list, len_list, GKB_flag, max_err) - def logic_forward(self, pseudo_labels): - pass - def _find_candidate_GKB(self, pred_res, key): potential_candidates = self.base[len(pred_res)] key_list = list(potential_candidates.keys()) @@ -331,15 +318,15 @@ class RegKB(KBBase): class HWF_KB(RegKB): def __init__( - self, GKB_flag=False, + self, pseudo_label_list=['1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', 'times', 'div'], len_list=[1, 3, 5, 7], + GKB_flag=False, max_err=1e-3 ): - super().__init__(GKB_flag, pseudo_label_list, len_list, max_err) + super().__init__(pseudo_label_list, len_list, GKB_flag, max_err) - # TODOï¼šåº”è¯¥æ˜¯é™æ€æ–¹æ³• - def valid_candidate(self, formula): + def _valid_candidate(self, formula): if len(formula) % 2 == 0: return False for i in range(len(formula)): @@ -350,7 +337,7 @@ class HWF_KB(RegKB): return True def logic_forward(self, formula): - if not self.valid_candidate(formula): + if not self._valid_candidate(formula): return np.inf mapping = { '1': '1', @@ -374,5 +361,4 @@ class HWF_KB(RegKB): import time if __name__ == "__main__": - pass - + pass \ No newline at end of file diff --git a/abl/utils/utils.py b/abl/utils/utils.py index acc7f94..d986065 100644 --- a/abl/utils/utils.py +++ b/abl/utils/utils.py @@ -1,16 +1,15 @@ import numpy as np from .plog import INFO from collections import OrderedDict +from itertools import chain -# for multiple predictions, modify from `learn_add.py` +# for multiple predictions def flatten(l): - # return [item for sublist in l for item in flatten(sublist)] if isinstance(l, (list, tuple)) else [l] if not isinstance(l[0], (list, tuple)): return l - # TODO ç¨å¾®å¯¹æ¯”一下和itertools.chain.from_iterable(nested_list)的速度区别,看看哪个好 - return [item for sublist in l for item in sublist] if isinstance(l, (list, tuple)) else [l] + return list(chain.from_iterable(l)) -# for multiple predictions, modify from `learn_add.py` +# for multiple predictions def reform_idx(flatten_pred_res, save_pred_res): re = [] i = 0 From b75b2897b953353ddade8afae51499367a21b0a8 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 7 Mar 2023 00:27:49 +0000 Subject: [PATCH 180/601] Rearrange address_by_idx to abducer_base --- abl/abducer/abducer_base.py | 10 ++++++---- abl/framework_hed.py | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index bd76831..cf14bb7 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -64,7 +64,7 @@ class AbducerBase(abc.ABC): score = 0 for idx in range(len(pred_res)): address_idx = [i for i, flag in enumerate(all_address_flag[idx]) if flag != 0] - candidate = self.kb.address_by_idx([pred_res[idx]], key[idx], address_idx, True) + candidate = self.address_by_idx([pred_res[idx]], key[idx], address_idx) if len(candidate) > 0: score += 1 return score @@ -72,7 +72,7 @@ class AbducerBase(abc.ABC): def _zoopt_address_score(self, pred_res, key, sol): if not self.multiple_predictions: address_idx = [idx for idx, i in enumerate(sol.get_x()) if i != 0] - candidates = self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) + candidates = self.address_by_idx(pred_res, key, address_idx) return 1 if len(candidates) > 0 else 0 else: return self._zoopt_score_multiple(pred_res, key, sol.get_x()) @@ -115,6 +115,9 @@ class AbducerBase(abc.ABC): key = tuple(key) self.cache_min_address_num[(tuple(pred_res), key)] = min_address_num self.cache_candidates[(tuple(pred_res), key, address_num)] = candidates + + def address_by_idx(self, pred_res, key, address_idx): + return self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) def abduce(self, data, max_address_num=-1, require_more_address=0): pred_res, pred_res_prob, key = data @@ -129,7 +132,7 @@ class AbducerBase(abc.ABC): if self.zoopt: solution = self.zoopt_get_solution(pred_res, key, max_address_num) address_idx = [idx for idx, i in enumerate(solution) if i != 0] - candidates = self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) + candidates = self.address_by_idx(pred_res, key, address_idx) address_num = int(solution.sum()) min_address_num = address_num else: @@ -156,7 +159,6 @@ class AbducerBase(abc.ABC): def __call__(self, Z, Y, max_address_num=-1, require_more_address=0): return self.batch_abduce(Z, Y, max_address_num, require_more_address) - if __name__ == '__main__': from kb import add_KB, prolog_KB, HWF_KB diff --git a/abl/framework_hed.py b/abl/framework_hed.py index a823b13..3f09ff6 100644 --- a/abl/framework_hed.py +++ b/abl/framework_hed.py @@ -158,7 +158,7 @@ def abduce_and_train(model, abducer, mapping, train_X_true, select_num): for idx in range(len(pred_res)): address_idx = [i for i, flag in enumerate(all_address_flag[idx]) if flag != 0] - candidate = abducer.kb.address_by_idx([pred_res[idx]], None, address_idx, True) + candidate = abducer.address_by_idx([pred_res[idx]], None, address_idx) if len(candidate) > 0: consistent_idx_tmp.append(idx) consistent_pred_res_tmp.append(candidate[0][0]) From f65a277e4d2f3faef35b5d805898e8a1bb579dd0 Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Tue, 7 Mar 2023 09:31:46 +0800 Subject: [PATCH 181/601] complete knn model for HED --- example.py | 59 ++++--- framework_hed_knn.py | 407 +++++++++++++++++++++++++++++++++++++++++++ utils/utils.py | 79 ++++++--- 3 files changed, 502 insertions(+), 43 deletions(-) create mode 100644 framework_hed_knn.py diff --git a/example.py b/example.py index 30c50fc..3751db3 100644 --- a/example.py +++ b/example.py @@ -11,12 +11,14 @@ # ================================================================# from utils.plog import logger, INFO +from utils.utils import reduce_dimension import torch.nn as nn import torch from models.nn import LeNet5, SymbolNet from models.basic_model import BasicModel, BasicDataset from models.wabl_models import DecisionTree, WABLBasicModel +from sklearn.neighbors import KNeighborsClassifier from multiprocessing import Pool from abducer.abducer_base import AbducerBase @@ -25,6 +27,7 @@ from datasets.mnist_add.get_mnist_add import get_mnist_add from datasets.hwf.get_hwf import get_hwf from datasets.hed.get_hed import get_hed, split_equation import framework_hed +import framework_hed_knn def run_test(): @@ -41,29 +44,45 @@ def run_test(): total_train_data = get_hed(train=True) train_data, val_data = split_equation(total_train_data, 3, 1) test_data = get_hed(train=False) - - # cls = LeNet5(num_classes=len(kb.pseudo_label_list), image_size=(train_data[0][0][0].shape[1:])) - cls = SymbolNet(num_classes=len(kb.pseudo_label_list)) - device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - - framework_hed.hed_pretrain(kb, cls, recorder) - - criterion = nn.CrossEntropyLoss() - optimizer = torch.optim.RMSprop(cls.parameters(), lr=0.001, weight_decay=1e-6) - # optimizer = torch.optim.Adam(cls.parameters(), lr=0.00001, betas=(0.9, 0.99)) - - - base_model = BasicModel(cls, criterion, optimizer, device, save_interval=1, save_dir=recorder.save_dir, batch_size=32, num_epochs=10, recorder=recorder) + + # ======================== non-NN model ========================== # + reduce_dimension(train_data) + reduce_dimension(val_data) + reduce_dimension(test_data) + base_model = KNeighborsClassifier(n_neighbors=3) + pretrain_data_X, pretrain_data_Y = framework_hed_knn.hed_pretrain(base_model) model = WABLBasicModel(base_model, kb.pseudo_label_list) - - # train_X, train_Z, train_Y = get_mnist_add(train = True, get_pseudo_label = True) - # test_X, test_Z, test_Y = get_mnist_add(train = False, get_pseudo_label = True) + model, mapping = framework_hed_knn.train_with_rule( + model, abducer, train_data, val_data, (pretrain_data_X, pretrain_data_Y), select_num=10, min_len=5, max_len=8 + ) + framework_hed_knn.hed_test( + model, abducer, mapping, train_data, test_data, min_len=5, max_len=8 + ) + # ============================ End =============================== # + + # ========================== NN model ============================ # + # # cls = LeNet5(num_classes=len(kb.pseudo_label_list), image_size=(train_data[0][0][0].shape[1:])) + # cls = SymbolNet(num_classes=len(kb.pseudo_label_list)) + # device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + # framework_hed.hed_pretrain(kb, cls, recorder) + + # criterion = nn.CrossEntropyLoss() + # optimizer = torch.optim.RMSprop(cls.parameters(), lr=0.001, weight_decay=1e-6) + # # optimizer = torch.optim.Adam(cls.parameters(), lr=0.00001, betas=(0.9, 0.99)) + + # base_model = BasicModel(cls, criterion, optimizer, device, save_interval=1, save_dir=recorder.save_dir, batch_size=32, num_epochs=10, recorder=recorder) + # model = WABLBasicModel(base_model, kb.pseudo_label_list) + + # # train_X, train_Z, train_Y = get_mnist_add(train = True, get_pseudo_label = True) + # # test_X, test_Z, test_Y = get_mnist_add(train = False, get_pseudo_label = True) - # train_data = get_hwf(train = True, get_pseudo_label = True) - # test_data = get_hwf(train = False, get_pseudo_label = True) + # # train_data = get_hwf(train = True, get_pseudo_label = True) + # # test_data = get_hwf(train = False, get_pseudo_label = True) - model, mapping = framework_hed.train_with_rule(model, abducer, train_data, val_data, select_num=10, min_len=5, max_len=8) - framework_hed.hed_test(model, abducer, mapping, train_data, test_data, min_len=5, max_len=8) + # model, mapping = framework_hed.train_with_rule(model, abducer, train_data, val_data, select_num=10, min_len=5, max_len=8) + # framework_hed.hed_test(model, abducer, mapping, train_data, test_data, min_len=5, max_len=8) + # ============================ End =============================== # recorder.dump() return True diff --git a/framework_hed_knn.py b/framework_hed_knn.py new file mode 100644 index 0000000..a5e5506 --- /dev/null +++ b/framework_hed_knn.py @@ -0,0 +1,407 @@ +# coding: utf-8 +# ================================================================# +# Copyright (C) 2021 Freecss All rights reserved. +# +# File Name :framework.py +# Author :freecss +# Email :karlfreecss@gmail.com +# Created Date :2021/06/07 +# Description : +# +# ================================================================# + +import pickle as pk +import torch +import torch.nn as nn +import numpy as np +import os + +from utils.plog import INFO, DEBUG, clocker +from utils.utils import ( + flatten, + reform_idx, + block_sample, + gen_mappings, + mapping_res, + remapping_res, + extract_feature, +) + +from models.nn import MLP, SymbolNetAutoencoder +from models.basic_model import BasicModel, BasicDataset +from datasets.hed.get_hed import get_pretrain_data + + +def result_statistics(pred_Z, Z, Y, logic_forward, char_acc_flag): + result = {} + if char_acc_flag: + char_acc_num = 0 + char_num = 0 + for pred_z, z in zip(pred_Z, Z): + char_num += len(z) + for zidx in range(len(z)): + if pred_z[zidx] == z[zidx]: + char_acc_num += 1 + char_acc = char_acc_num / char_num + result["Character level accuracy"] = char_acc + + abl_acc_num = 0 + for pred_z, y in zip(pred_Z, Y): + if logic_forward(pred_z) == y: + abl_acc_num += 1 + abl_acc = abl_acc_num / len(Y) + result["ABL accuracy"] = abl_acc + + return result + + +def filter_data(X, abduced_Z): + finetune_Z = [] + finetune_X = [] + for abduced_x, abduced_z in zip(X, abduced_Z): + if abduced_z is not []: + finetune_X.append(abduced_x) + finetune_Z.append(abduced_z) + return finetune_X, finetune_Z + + +def hed_pretrain(cls, image_size=(28, 28, 1)): + import cv2 + + INFO("Pretrain Start") + pretrain_data_X, pretrain_data_Y = [], [] + for i, label in enumerate(["0", "1", "10", "11"]): + label_path = os.path.join("./datasets/hed/dataset/mnist_images", label) + img_path_list = os.listdir(label_path) + for j in range(10): + img = cv2.imread( + os.path.join(label_path, img_path_list[j]), cv2.IMREAD_GRAYSCALE + ) + img = np.array(cv2.resize(img, (image_size[1], image_size[0])), np.float32) + img = (img - 127) / 128.0 + pretrain_data_X.append( + extract_feature(img.reshape((1, image_size[0], image_size[1]))) + ) + pretrain_data_Y.append(i) + cls.fit(pretrain_data_X, pretrain_data_Y) + import random + + for i, label in enumerate(["0", "1", "10", "11"]): + label_path = os.path.join("./datasets/hed/dataset/mnist_images", label) + img_path_list = os.listdir(label_path) + cnt = 0 + for j in range(50): + img = cv2.imread( + os.path.join(label_path, random.choice(img_path_list)), + cv2.IMREAD_GRAYSCALE, + ) + img = np.array(cv2.resize(img, (image_size[1], image_size[0])), np.float32) + img = (img - 127) / 128.0 + predict_label = cls.predict( + [extract_feature(img.reshape((1, image_size[0], image_size[1])))] + ) + # predict_label = cls.predict_proba( + # [ + # extract_feature( + # np.array(img, dtype=np.float32).reshape( + # (1, image_size[0], image_size[1]) + # ) + # ) + # ] + # ).argmax(axis=1) + + if predict_label == i: + cnt += 1 + INFO( + "%d predict accuracy is " % i, + cnt / 50, + ) + + return pretrain_data_X, pretrain_data_Y + + +def _get_char_acc(model, X, consistent_pred_res, mapping): + original_pred_res = model.predict(X)["cls"] + pred_res = flatten(mapping_res(original_pred_res, mapping)) + INFO("Current model's output: ", pred_res) + INFO("Abduced labels: ", flatten(consistent_pred_res)) + assert len(pred_res) == len(flatten(consistent_pred_res)) + return sum( + [ + pred_res[idx] == flatten(consistent_pred_res)[idx] + for idx in range(len(pred_res)) + ] + ) / len(pred_res) + + +def abduce_and_train(model, abducer, mapping, train_X_true, pretrain_data, select_num): + select_idx = np.random.randint(len(train_X_true), size=select_num) + X = [] + for idx in select_idx: + X.append(train_X_true[idx]) + + original_pred_res = model.predict(X)["cls"] + + if mapping == None: + mappings = gen_mappings(["+", "=", 0, 1], ["+", "=", 0, 1]) + else: + mappings = [mapping] + + consistent_idx = [] + consistent_pred_res = [] + + for m in mappings: + pred_res = mapping_res(original_pred_res, m) + max_abduce_num = 20 + solution = abducer.zoopt_get_solution( + pred_res, [1] * len(pred_res), max_abduce_num + ) + all_address_flag = reform_idx(solution, pred_res) + + consistent_idx_tmp = [] + consistent_pred_res_tmp = [] + + for idx in range(len(pred_res)): + address_idx = [ + i for i, flag in enumerate(all_address_flag[idx]) if flag != 0 + ] + candidate = abducer.kb.address_by_idx([pred_res[idx]], 1, address_idx, True) + if len(candidate) > 0: + consistent_idx_tmp.append(idx) + consistent_pred_res_tmp.append(candidate[0][0]) + + if len(consistent_idx_tmp) > len(consistent_idx): + consistent_idx = consistent_idx_tmp + consistent_pred_res = consistent_pred_res_tmp + if len(mappings) > 1: + mapping = m + + if len(consistent_idx) == 0: + return 0, 0, None + + if len(mappings) > 1: + INFO("Final mapping is: ", mapping) + + INFO("Train pool size is:", len(flatten(consistent_pred_res))) + INFO("Start to use abduced pseudo label to train model...") + pretrain_data_X, pretrain_data_Y = pretrain_data + pretrain_mappping = {0: 0, 1: 1, 2: "+", 3: "="} + pretrain_data_X = [[X] for X in pretrain_data_X] + pretrain_data_Y = [[pretrain_mappping[Y]] for Y in pretrain_data_Y] + model.train( + [X[idx] for idx in consistent_idx] + pretrain_data_X, + remapping_res(consistent_pred_res + pretrain_data_Y, mapping), + ) + + consistent_acc = len(consistent_idx) / select_num + char_acc = _get_char_acc( + model, [X[idx] for idx in consistent_idx], consistent_pred_res, mapping + ) + INFO("consistent_acc is %s, char_acc is %s" % (consistent_acc, char_acc)) + return consistent_acc, char_acc, mapping + + +def _remove_duplicate_rule(rule_dict): + add_nums_dict = {} + for r in list(rule_dict): + add_nums = str(r.split("]")[0].split("[")[1]) + str( + r.split("]")[1].split("[")[1] + ) # r = 'my_op([1], [0], [1, 0])' then add_nums = '10' + if add_nums in add_nums_dict: + old_r = add_nums_dict[add_nums] + if rule_dict[r] >= rule_dict[old_r]: + rule_dict.pop(old_r) + add_nums_dict[add_nums] = r + else: + rule_dict.pop(r) + else: + add_nums_dict[add_nums] = r + return list(rule_dict) + + +def get_rules_from_data( + model, abducer, mapping, train_X_true, samples_per_rule, samples_num +): + rules = [] + for _ in range(samples_num): + while True: + select_idx = np.random.randint(len(train_X_true), size=samples_per_rule) + X = [] + for idx in select_idx: + X.append(train_X_true[idx]) + original_pred_res = model.predict(X)["cls"] + pred_res = mapping_res(original_pred_res, mapping) + + consistent_idx = [] + consistent_pred_res = [] + for idx in range(len(pred_res)): + if abducer.kb.logic_forward([pred_res[idx]]): + consistent_idx.append(idx) + consistent_pred_res.append(pred_res[idx]) + + if len(consistent_pred_res) != 0: + rule = abducer.abduce_rules(consistent_pred_res) + if rule != None: + break + rules.append(rule) + + all_rule_dict = {} + for rule in rules: + for r in rule: + all_rule_dict[r] = 1 if r not in all_rule_dict else all_rule_dict[r] + 1 + rule_dict = {rule: cnt for rule, cnt in all_rule_dict.items() if cnt >= 5} + rules = _remove_duplicate_rule(rule_dict) + + return rules + + +def _get_consist_rule_acc(model, abducer, mapping, rules, X): + cnt = 0 + for x in X: + original_pred_res = model.predict([x])["cls"] + pred_res = flatten(mapping_res(original_pred_res, mapping)) + if abducer.kb.consist_rule(pred_res, rules): + cnt += 1 + return cnt / len(X) + + +def train_with_rule( + model, + abducer, + train_data, + val_data, + pretrain_data, + select_num=10, + min_len=5, + max_len=8, +): + train_X = train_data + val_X = val_data + + samples_num = 50 + samples_per_rule = 3 + + # Start training / for each length of equations + for equation_len in range(min_len, max_len): + INFO( + "============== equation_len: %d-%d ================" + % (equation_len, equation_len + 1) + ) + train_X_true = train_X[1][equation_len] + train_X_false = train_X[0][equation_len] + val_X_true = val_X[1][equation_len] + val_X_false = val_X[0][equation_len] + + train_X_true.extend(train_X[1][equation_len + 1]) + train_X_false.extend(train_X[0][equation_len + 1]) + val_X_true.extend(val_X[1][equation_len + 1]) + val_X_false.extend(val_X[0][equation_len + 1]) + + condition_cnt = 0 + while True: + if equation_len == min_len: + mapping = None + + # Abduce and train NN + consistent_acc, char_acc, mapping = abduce_and_train( + model, abducer, mapping, train_X_true, pretrain_data, select_num + ) + if consistent_acc == 0: + continue + + # Test if we can use mlp to evaluate + if consistent_acc >= 0.9 and char_acc >= 0.9: + condition_cnt += 1 + else: + condition_cnt = 0 + + # The condition has been satisfied continuously five times + if condition_cnt >= 5: + INFO("Now checking if we can go to next course") + rules = get_rules_from_data( + model, abducer, mapping, train_X_true, samples_per_rule, samples_num + ) + INFO("Learned rules from data:", rules) + + true_consist_rule_acc = _get_consist_rule_acc( + model, abducer, mapping, rules, val_X_true + ) + false_consist_rule_acc = _get_consist_rule_acc( + model, abducer, mapping, rules, val_X_false + ) + + INFO( + "consist_rule_acc is %f, %f\n" + % (true_consist_rule_acc, false_consist_rule_acc) + ) + # decide next course or restart + if true_consist_rule_acc > 0.9 and false_consist_rule_acc < 0.1: + break + else: + if equation_len == min_len: + # model.cls_list[0].model.load_state_dict( + # torch.load("./weights/pretrain_weights.pth") + # ) + pretrain_data_X, pretrain_data_Y = pretrain_data + model.cls_list[0].fit(pretrain_data_X, pretrain_data_Y) + else: + pretrain_data_X, pretrain_data_Y = pretrain_data + model.cls_list[0].fit(pretrain_data_X, pretrain_data_Y) + # model.cls_list[0].model.load_state_dict( + # torch.load("./weights/weights_%d.pth" % (equation_len - 1)) + # ) + condition_cnt = 0 + INFO("Reload Model and retrain") + + return model, mapping + + +def hed_test(model, abducer, mapping, train_data, test_data, min_len=5, max_len=8): + train_X = train_data + test_X = test_data + + # Calcualte how many equations should be selected in each length + # for each length, there are equation_samples_num[equation_len] rules + print("Now begin to train final mlp model") + equation_samples_num = [] + len_cnt = max_len - min_len + 1 + samples_num = 50 + equation_samples_num += [0] * min_len + if samples_num % len_cnt == 0: + equation_samples_num += [samples_num // len_cnt] * len_cnt + else: + equation_samples_num += [samples_num // len_cnt] * len_cnt + equation_samples_num[-1] += samples_num % len_cnt + assert sum(equation_samples_num) == samples_num + + # Abduce rules + rules = [] + samples_per_rule = 3 + for equation_len in range(min_len, max_len + 1): + equation_rules = get_rules_from_data( + model, + abducer, + mapping, + train_X[1][equation_len], + samples_per_rule, + equation_samples_num[equation_len], + ) + rules.extend(equation_rules) + rules = list(set(rules)) + INFO("Learned rules from data:", rules) + + for equation_len in range(5, 27): + true_consist_rule_acc = _get_consist_rule_acc( + model, abducer, mapping, rules, test_X[1][equation_len] + ) + false_consist_rule_acc = _get_consist_rule_acc( + model, abducer, mapping, rules, test_X[0][equation_len] + ) + INFO( + "consist_rule_acc of testing length %d equations are %f, %f" + % (equation_len, true_consist_rule_acc, false_consist_rule_acc) + ) + + +if __name__ == "__main__": + pass diff --git a/utils/utils.py b/utils/utils.py index 1138361..5cd433d 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -1,11 +1,18 @@ +import torch +import torch.nn as nn import numpy as np from utils.plog import INFO from collections import OrderedDict # for multiple predictions, modify from `learn_add.py` def flatten(l): - return [item for sublist in l for item in flatten(sublist)] if isinstance(l, list) else [l] - + return ( + [item for sublist in l for item in flatten(sublist)] + if isinstance(l, list) + else [l] + ) + + # for multiple predictions, modify from `learn_add.py` def reform_idx(flatten_pred_res, save_pred_res): re = [] @@ -20,10 +27,12 @@ def reform_idx(flatten_pred_res, save_pred_res): i = i + j return re + def hamming_dist(A, B): B = np.array(B) - A = np.expand_dims(A, axis = 0).repeat(axis=0, repeats=(len(B))) - return np.sum(A != B, axis = 1) + A = np.expand_dims(A, axis=0).repeat(axis=0, repeats=(len(B))) + return np.sum(A != B, axis=1) + def confidence_dist(A, B): B = np.array(B) @@ -31,10 +40,10 @@ def confidence_dist(A, B): A = np.expand_dims(A, axis=0) A = A.repeat(axis=0, repeats=(len(B))) rows = np.array(range(len(B))) - rows = np.expand_dims(rows, axis = 1).repeat(axis = 1, repeats = len(B[0])) + rows = np.expand_dims(rows, axis=1).repeat(axis=1, repeats=len(B[0])) cols = np.array(range(len(B[0]))) - cols = np.expand_dims(cols, axis = 0).repeat(axis = 0, repeats = len(B)) - return 1 - np.prod(A[rows, cols, B], axis = 1) + cols = np.expand_dims(cols, axis=0).repeat(axis=0, repeats=len(B)) + return 1 - np.prod(A[rows, cols, B], axis=1) def block_sample(X, Z, Y, sample_num, epoch_idx): @@ -51,32 +60,36 @@ def block_sample(X, Z, Y, sample_num, epoch_idx): def gen_mappings(chars, symbs): - n_char = len(chars) - n_symbs = len(symbs) - if n_char != n_symbs: - print('Characters and symbols size dosen\'t match.') - return - from itertools import permutations - mappings = [] - # returned mappings - perms = permutations(symbs) - for p in perms: - mappings.append(dict(zip(chars, list(p)))) - return mappings + n_char = len(chars) + n_symbs = len(symbs) + if n_char != n_symbs: + print("Characters and symbols size dosen't match.") + return + from itertools import permutations + + mappings = [] + # returned mappings + perms = permutations(symbs) + for p in perms: + mappings.append(dict(zip(chars, list(p)))) + return mappings + def mapping_res(original_pred_res, m): return [[m[symbol] for symbol in formula] for formula in original_pred_res] + def remapping_res(pred_res, m): remapping = {} for key, value in m.items(): remapping[value] = key return [[remapping[symbol] for symbol in formula] for formula in pred_res] + def check_equal(a, b): if isinstance(a, (int, float)) and isinstance(b, (int, float)): return abs(a - b) <= 1e-3 - + if isinstance(a, list) and isinstance(b, list): if len(a) != len(b): return False @@ -84,6 +97,26 @@ def check_equal(a, b): if not check_equal(a[i], b[i]): return False return True - - else: - return a == b + + else: + return a == b + + +def extract_feature(img): + extractor = nn.AvgPool2d(2, stride=2) + feature_map = np.array(extractor(torch.Tensor(img))) + return feature_map.reshape((-1,)) + return np.concatenate( + (np.squeeze(np.sum(img, axis=1)), np.squeeze(np.sum(img, axis=2))), axis=0 + ) + + +def reduce_dimension(data): + for truth_value in [0, 1]: + for equation_len in range(5, 27): + equations = data[truth_value][equation_len] + reduced_equations = [ + [extract_feature(symbol_img) for symbol_img in equation] + for equation in equations + ] + data[truth_value][equation_len] = reduced_equations From 935a06f499427c2aa3a2da12c311d92adadfafdd Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 7 Mar 2023 14:39:36 +0800 Subject: [PATCH 182/601] Remove default parameters in RegKB --- abl/abducer/kb.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 5b82f03..9009940 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -291,7 +291,7 @@ class prolog_KB(KBBase): class RegKB(KBBase): - def __init__(self, pseudo_label_list=None, len_list=None, GKB_flag=False, max_err=1e-3): + def __init__(self, pseudo_label_list, len_list, GKB_flag, max_err): super().__init__(pseudo_label_list, len_list, GKB_flag, max_err) def _find_candidate_GKB(self, pred_res, key): @@ -361,4 +361,4 @@ class HWF_KB(RegKB): import time if __name__ == "__main__": - pass \ No newline at end of file + pass From 5290ebd804984c87481c2693d44552ef2eceaa62 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 7 Mar 2023 15:58:56 +0800 Subject: [PATCH 183/601] Modify mapping in HWF_KB --- abl/abducer/kb.py | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 9009940..d656e41 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -339,26 +339,11 @@ class HWF_KB(RegKB): def logic_forward(self, formula): if not self._valid_candidate(formula): return np.inf - mapping = { - '1': '1', - '2': '2', - '3': '3', - '4': '4', - '5': '5', - '6': '6', - '7': '7', - '8': '8', - '9': '9', - '+': '+', - '-': '-', - 'times': '*', - 'div': '/', - } + mapping = {str(i): str(i) for i in range(1, 10)} + mapping.update({'+': '+', '-': '-', 'times': '*', 'div': '/'}) formula = [mapping[f] for f in formula] return eval(''.join(formula)) -import time - if __name__ == "__main__": pass From 34eabfb61367a5bf64990de360634c151f74913f Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Tue, 7 Mar 2023 23:04:01 +0800 Subject: [PATCH 184/601] update todo in abducer --- abl/abducer/abducer_base.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index cf14bb7..c5c21fd 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -40,7 +40,8 @@ class AbducerBase(abc.ABC): if self.multiple_predictions: pred_res_prob = flatten(pred_res_prob) candidates = [flatten(c) for c in candidates] - + + # TODO:这里应该在类创建时就æå‰å­˜å¥½ï¼Œæ¯æ¬¡éƒ½é‡æ–°è®¡ç®—也太费时了 mapping = dict(zip(self.kb.pseudo_label_list, list(range(len(self.kb.pseudo_label_list))))) candidates = [list(map(lambda x: mapping[x], c)) for c in candidates] return confidence_dist(pred_res_prob, candidates) @@ -53,15 +54,22 @@ class AbducerBase(abc.ABC): else: cost_list = self._get_cost_list(pred_res, pred_res_prob, candidates) + # TODO:这里很怪,按ç†argmin就行了 min_address_num = np.min(cost_list) idxs = np.where(cost_list == min_address_num)[0] + # TODO:这里也很怪,å–ç¬¬ä¸€ä¸ªå°±è¡Œäº†å§ candidate = [candidates[idx] for idx in idxs][0] return candidate + # TODO:这里对zoopt的使用ä¸å¤ªå¯¹ã€‚zooptæƒ³è¦æ±‚解的是,修改哪几个符å·çš„ä½ç½®ï¼ˆè¡¨ç¤ºä¸º01串),能得到“最好â€çš„å绎结果,ç†è®ºä¸Šèƒ½æ¯”kb._address中的枚举法æœç´¢æ¬¡æ•°æ›´å°‘。 + # TODO:而这里“最好â€çš„定义,和ä¸ç”¨zooptæœç´¢æ—¶çš„定义一致,目å‰è¦ä¹ˆ'hamming'ã€è¦ä¹ˆ'confidence' + # TODO: 因此,zoopt的作用,有点类似èžåˆkb(得到若干å绎结果)和abducer(选一个å绎结果)的功能。 + # TODO:下é¢ä¸¤ä¸ªå‡½æ•°çš„score,应该是得到candidatesåŽï¼Œè°ƒç”¨_get_one_candidate计算?(没细看) # for zoopt def _zoopt_score_multiple(self, pred_res, key, solution): all_address_flag = reform_idx(solution, pred_res) score = 0 + # TODO:原版ablçš„score是这样计算的å—,我记得没有把若干预测结果拆开然åŽåˆ†åˆ«addressçš„æ“作 for idx in range(len(pred_res)): address_idx = [i for i, flag in enumerate(all_address_flag[idx]) if flag != 0] candidate = self.address_by_idx([pred_res[idx]], key[idx], address_idx) @@ -94,6 +102,8 @@ class AbducerBase(abc.ABC): return solution + # TODO:cache移到kb里å§ï¼Œæ¯”如_abduce_by_search里,它存的是若干åç»Žç»“æžœï¼Œä¸æ¶‰åŠä»Žè‹¥å¹²å绎结果中选一个 + # TODO:python也有自带的用装饰器实现的缓存方法,比如functools.lru_cacheã€cachetools等,åŽé¢ç¨å¾®è°ƒç ”一下和手动缓存的优劣,看看用哪个好 def _get_cache(self, data, max_address_num, require_more_address): pred_res, pred_res_prob, key = data if self.multiple_predictions: From 19f29e40880ff76af8c445a443663f260cfee397 Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Wed, 8 Mar 2023 17:38:41 +0800 Subject: [PATCH 185/601] Update abducer_base.py and related files --- abl/abducer/abducer_base.py | 108 ++++++++++-------------------------- abl/abducer/kb.py | 61 +++++++++++++++----- abl/framework_hed.py | 2 +- 3 files changed, 78 insertions(+), 93 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index c5c21fd..a70db14 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -16,17 +16,14 @@ from zoopt import Dimension, Objective, Parameter, Opt from ..utils.utils import confidence_dist, flatten, reform_idx, hamming_dist class AbducerBase(abc.ABC): - def __init__(self, kb, dist_func='confidence', zoopt=False, multiple_predictions=False, cache=True): + def __init__(self, kb, dist_func='hamming', zoopt=False, multiple_predictions=False): self.kb = kb assert dist_func == 'hamming' or dist_func == 'confidence' self.dist_func = dist_func self.zoopt = zoopt self.multiple_predictions = multiple_predictions - self.cache = cache - - if self.cache: - self.cache_min_address_num = {} - self.cache_candidates = {} + if dist_func == 'confidence': + self.mapping = dict(zip(self.kb.pseudo_label_list, list(range(len(self.kb.pseudo_label_list))))) def _get_cost_list(self, pred_res, pred_res_prob, candidates): if self.dist_func == 'hamming': @@ -40,10 +37,7 @@ class AbducerBase(abc.ABC): if self.multiple_predictions: pred_res_prob = flatten(pred_res_prob) candidates = [flatten(c) for c in candidates] - - # TODO:这里应该在类创建时就æå‰å­˜å¥½ï¼Œæ¯æ¬¡éƒ½é‡æ–°è®¡ç®—也太费时了 - mapping = dict(zip(self.kb.pseudo_label_list, list(range(len(self.kb.pseudo_label_list))))) - candidates = [list(map(lambda x: mapping[x], c)) for c in candidates] + candidates = [list(map(lambda x: self.mapping[x], c)) for c in candidates] return confidence_dist(pred_res_prob, candidates) def _get_one_candidate(self, pred_res, pred_res_prob, candidates): @@ -54,46 +48,38 @@ class AbducerBase(abc.ABC): else: cost_list = self._get_cost_list(pred_res, pred_res_prob, candidates) - # TODO:这里很怪,按ç†argmin就行了 - min_address_num = np.min(cost_list) - idxs = np.where(cost_list == min_address_num)[0] - # TODO:这里也很怪,å–ç¬¬ä¸€ä¸ªå°±è¡Œäº†å§ - candidate = [candidates[idx] for idx in idxs][0] + candidate = candidates[np.argmin(cost_list)] return candidate - # TODO:这里对zoopt的使用ä¸å¤ªå¯¹ã€‚zooptæƒ³è¦æ±‚解的是,修改哪几个符å·çš„ä½ç½®ï¼ˆè¡¨ç¤ºä¸º01串),能得到“最好â€çš„å绎结果,ç†è®ºä¸Šèƒ½æ¯”kb._address中的枚举法æœç´¢æ¬¡æ•°æ›´å°‘。 - # TODO:而这里“最好â€çš„定义,和ä¸ç”¨zooptæœç´¢æ—¶çš„定义一致,目å‰è¦ä¹ˆ'hamming'ã€è¦ä¹ˆ'confidence' - # TODO: 因此,zoopt的作用,有点类似èžåˆkb(得到若干å绎结果)和abducer(选一个å绎结果)的功能。 - # TODO:下é¢ä¸¤ä¸ªå‡½æ•°çš„score,应该是得到candidatesåŽï¼Œè°ƒç”¨_get_one_candidate计算?(没细看) - # for zoopt - def _zoopt_score_multiple(self, pred_res, key, solution): - all_address_flag = reform_idx(solution, pred_res) - score = 0 - # TODO:原版ablçš„score是这样计算的å—,我记得没有把若干预测结果拆开然åŽåˆ†åˆ«addressçš„æ“作 - for idx in range(len(pred_res)): - address_idx = [i for i, flag in enumerate(all_address_flag[idx]) if flag != 0] - candidate = self.address_by_idx([pred_res[idx]], key[idx], address_idx) - if len(candidate) > 0: - score += 1 - return score - - def _zoopt_address_score(self, pred_res, key, sol): + def _zoopt_address_score(self, pred_res, pred_res_prob, key, sol): if not self.multiple_predictions: - address_idx = [idx for idx, i in enumerate(sol.get_x()) if i != 0] + address_idx = np.where(sol.get_x() != 0)[0] candidates = self.address_by_idx(pred_res, key, address_idx) - return 1 if len(candidates) > 0 else 0 + if len(candidates) > 0: + return np.min(self._get_cost_list(pred_res, pred_res_prob, candidates)) + else: + return len(pred_res) else: - return self._zoopt_score_multiple(pred_res, key, sol.get_x()) - + all_address_flag = reform_idx(sol.get_x(), pred_res) + score = 0 + for idx in range(len(pred_res)): + address_idx = np.where(all_address_flag[idx] != 0)[0] + candidates = self.address_by_idx([pred_res[idx]], key[idx], address_idx) + if len(candidates) > 0: + score += np.min(self._get_cost_list(pred_res[idx], pred_res_prob[idx], candidates)) + else: + score += len(pred_res) + return -self._zoopt_score_multiple(pred_res, key, sol.get_x()) + def _constrain_address_num(self, solution, max_address_num): x = solution.get_x() return max_address_num - x.sum() - def zoopt_get_solution(self, pred_res, key, max_address_num): + def zoopt_get_solution(self, pred_res, pred_res_prob, key, max_address_num): length = len(flatten(pred_res)) dimension = Dimension(size=length, regs=[[0, 1]] * length, tys=[False] * length) objective = Objective( - lambda sol: -self._zoopt_address_score(pred_res, key, sol), + lambda sol: self._zoopt_address_score(pred_res, pred_res_prob, key, sol), dim=dimension, constraint=lambda sol: self._constrain_address_num(sol, max_address_num), ) @@ -101,31 +87,7 @@ class AbducerBase(abc.ABC): solution = Opt.min(objective, parameter).get_x() return solution - - # TODO:cache移到kb里å§ï¼Œæ¯”如_abduce_by_search里,它存的是若干åç»Žç»“æžœï¼Œä¸æ¶‰åŠä»Žè‹¥å¹²å绎结果中选一个 - # TODO:python也有自带的用装饰器实现的缓存方法,比如functools.lru_cacheã€cachetools等,åŽé¢ç¨å¾®è°ƒç ”一下和手动缓存的优劣,看看用哪个好 - def _get_cache(self, data, max_address_num, require_more_address): - pred_res, pred_res_prob, key = data - if self.multiple_predictions: - pred_res = flatten(pred_res) - key = tuple(key) - if (tuple(pred_res), key) in self.cache_min_address_num: - address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), key)] + require_more_address) - if (tuple(pred_res), key, address_num) in self.cache_candidates: - candidates = self.cache_candidates[(tuple(pred_res), key, address_num)] - if self.zoopt: - return candidates[0] - else: - return self._get_one_candidate(pred_res, pred_res_prob, candidates) - return None - - def _set_cache(self, pred_res, key, min_address_num, address_num, candidates): - if self.multiple_predictions: - pred_res = flatten(pred_res) - key = tuple(key) - self.cache_min_address_num[(tuple(pred_res), key)] = min_address_num - self.cache_candidates[(tuple(pred_res), key, address_num)] = candidates - + def address_by_idx(self, pred_res, key, address_idx): return self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) @@ -134,27 +96,17 @@ class AbducerBase(abc.ABC): if max_address_num == -1: max_address_num = len(flatten(pred_res)) - if self.cache: - candidate = self._get_cache(data, max_address_num, require_more_address) - if candidate is not None: - return candidate - if self.zoopt: - solution = self.zoopt_get_solution(pred_res, key, max_address_num) - address_idx = [idx for idx, i in enumerate(solution) if i != 0] + solution = self.zoopt_get_solution(pred_res, pred_res_prob, key, max_address_num) + address_idx = np.where(solution != 0)[0] candidates = self.address_by_idx(pred_res, key, address_idx) - address_num = int(solution.sum()) - min_address_num = address_num else: - candidates, min_address_num, address_num = self.kb.abduce_candidates( + candidates = self.kb.abduce_candidates( pred_res, key, max_address_num, require_more_address, self.multiple_predictions ) candidate = self._get_one_candidate(pred_res, pred_res_prob, candidates) - if self.cache: - self._set_cache(pred_res, key, min_address_num, address_num, candidates) - return candidate def abduce_rules(self, pred_res): @@ -283,9 +235,9 @@ if __name__ == '__main__': print(kb.consist_rule([1, '+', 1, '=', 1, 0], rules), kb.consist_rule([1, '+', 1, '=', 1, 1], rules)) print() - res = abd.abduce((consist_exs, None, [None] * len(consist_exs))) + res = abd.abduce((consist_exs, [None] * len(consist_exs), [None] * len(consist_exs))) print(res) - res = abd.abduce((inconsist_exs, None, [None] * len(inconsist_exs))) + res = abd.abduce((inconsist_exs, [None] * len(consist_exs), [None] * len(inconsist_exs))) print(res) print() diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index d656e41..2a29d12 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -17,24 +17,30 @@ import numpy as np from collections import defaultdict from itertools import product, combinations -from ..utils.utils import flatten, reform_idx, hamming_dist, check_equal +from utils.utils import flatten, reform_idx, hamming_dist, check_equal from multiprocessing import Pool +from functools import lru_cache import pyswip class KBBase(ABC): - def __init__(self, pseudo_label_list, len_list=None, GKB_flag=False, max_err=0): + def __init__(self, pseudo_label_list, len_list=None, GKB_flag=False, max_err=0):#, abduce_cache=True): self.pseudo_label_list = pseudo_label_list self.len_list = len_list self.GKB_flag = GKB_flag self.max_err = max_err + # self.abduce_cache = abduce_cache if GKB_flag: self.base = {} X, Y = self._get_GKB() for x, y in zip(X, Y): self.base.setdefault(len(x), defaultdict(list))[y].append(x) + + # if abduce_cache: + # self.cache_min_address_num = {} + # self.cache_candidates = {} # For parallel version of _get_GKB def _get_XY_list(self, args): @@ -92,21 +98,21 @@ class KBBase(ABC): def _abduce_by_GKB(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): if self.base == {}: - return [], 0, 0 + return [] if not multiple_predictions: if len(pred_res) not in self.len_list: - return [], 0, 0 + return [] all_candidates = self._find_candidate_GKB(pred_res, key) if len(all_candidates) == 0: - return [], 0, 0 + return [] else: cost_list = hamming_dist(pred_res, all_candidates) min_address_num = np.min(cost_list) address_num = min(max_address_num, min_address_num + require_more_address) idxs = np.where(cost_list <= address_num)[0] candidates = [all_candidates[idx] for idx in idxs] - return candidates, min_address_num, address_num + return candidates else: min_address_num = 0 @@ -115,10 +121,10 @@ class KBBase(ABC): for p_res, k in zip(pred_res, key): if len(p_res) not in self.len_list: - return [], 0, 0 + return [] all_candidates = self._find_candidate_GKB(p_res, k) if len(all_candidates) == 0: - return [], 0, 0 + return [] else: all_candidates_save.append(all_candidates) cost_list = hamming_dist(p_res, all_candidates) @@ -126,13 +132,31 @@ class KBBase(ABC): cost_list_save.append(cost_list) multiple_all_candidates = [flatten(c) for c in product(*all_candidates_save)] - assert len(multiple_all_candidates[0]) == len(flatten(pred_res)) multiple_cost_list = np.array([sum(cost) for cost in product(*cost_list_save)]) - assert len(multiple_all_candidates) == len(multiple_cost_list) address_num = min(max_address_num, min_address_num + require_more_address) idxs = np.where(multiple_cost_list <= address_num)[0] candidates = [reform_idx(multiple_all_candidates[idx], pred_res) for idx in idxs] - return candidates, min_address_num, address_num + return candidates + + # TODO:python也有自带的用装饰器实现的缓存方法,比如functools.lru_cacheã€cachetools等,åŽé¢ç¨å¾®è°ƒç ”一下和手动缓存的优劣,看看用哪个好 + # def _get_abduce_cache(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): + # if multiple_predictions: + # pred_res = flatten(pred_res) + # key = tuple(key) + # if (tuple(pred_res), key) in self.cache_min_address_num: + # address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), key)] + require_more_address) + # if (tuple(pred_res), key, address_num) in self.cache_candidates: + # candidates = self.cache_candidates[(tuple(pred_res), key, address_num)] + # return candidates + # return None + + # def _set_abduce_cache(self, pred_res, key, min_address_num, address_num, candidates, multiple_predictions): + # if multiple_predictions: + # pred_res = flatten(pred_res) + # key = tuple(key) + # self.cache_min_address_num[(tuple(pred_res), key)] = min_address_num + # self.cache_candidates[(tuple(pred_res), key, address_num)] = candidates + def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): candidates = [] @@ -166,7 +190,13 @@ class KBBase(ABC): new_candidates += candidates return new_candidates + # @lru_cache(maxsize=100) def _abduce_by_search(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): + # if self.abduce_cache: + # candidates = self._get_abduce_cache(pred_res, key, max_address_num, require_more_address, multiple_predictions) + # if candidates is not None: + # return candidates + candidates = [] for address_num in range(len(flatten(pred_res)) + 1): @@ -182,15 +212,18 @@ class KBBase(ABC): break if address_num >= max_address_num: - return [], 0, 0 + return [] for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): if address_num > max_address_num: return candidates, min_address_num, address_num - 1 new_candidates = self._address(address_num, pred_res, key, multiple_predictions) candidates += new_candidates + + # if self.abduce_cache: + # self._set_abduce_cache(pred_res, key, min_address_num, address_num, candidates, multiple_predictions) - return candidates, min_address_num, address_num + return candidates def _dict_len(self, dic): if not self.GKB_flag: @@ -346,4 +379,4 @@ class HWF_KB(RegKB): if __name__ == "__main__": - pass + pass \ No newline at end of file diff --git a/abl/framework_hed.py b/abl/framework_hed.py index 3f09ff6..d339909 100644 --- a/abl/framework_hed.py +++ b/abl/framework_hed.py @@ -150,7 +150,7 @@ def abduce_and_train(model, abducer, mapping, train_X_true, select_num): for m in mappings: pred_res = mapping_res(original_pred_res, m) max_abduce_num = 20 - solution = abducer.zoopt_get_solution(pred_res, [None] * len(pred_res), max_abduce_num) + solution = abducer.zoopt_get_solution(pred_res, [None] * len(pred_res), [None] * len(pred_res), max_abduce_num) all_address_flag = reform_idx(solution, pred_res) consistent_idx_tmp = [] From 24ce8ff87ef318d57338cbcdb8da5da58b29a11a Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 8 Mar 2023 10:18:08 +0000 Subject: [PATCH 186/601] Update several files --- abl/abducer/abducer_base.py | 4 ++-- abl/framework_hed.py | 2 +- abl/utils/utils.py | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index a70db14..61cab25 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -68,8 +68,8 @@ class AbducerBase(abc.ABC): if len(candidates) > 0: score += np.min(self._get_cost_list(pred_res[idx], pred_res_prob[idx], candidates)) else: - score += len(pred_res) - return -self._zoopt_score_multiple(pred_res, key, sol.get_x()) + score += len(pred_res[idx]) + return score def _constrain_address_num(self, solution, max_address_num): x = solution.get_x() diff --git a/abl/framework_hed.py b/abl/framework_hed.py index d339909..ab88318 100644 --- a/abl/framework_hed.py +++ b/abl/framework_hed.py @@ -291,7 +291,7 @@ def train_with_rule(model, abducer, train_data, val_data, select_num=10, min_len INFO('consist_rule_acc is %f, %f\n' %(true_consist_rule_acc, false_consist_rule_acc)) # decide next course or restart - if true_consist_rule_acc > 0.9 and false_consist_rule_acc < 0.1: + if true_consist_rule_acc > 0.95 and false_consist_rule_acc < 0.1: torch.save(model.cls_list[0].model.state_dict(), "./weights/weights_%d.pth" % equation_len) break else: diff --git a/abl/utils/utils.py b/abl/utils/utils.py index d986065..d5209a6 100644 --- a/abl/utils/utils.py +++ b/abl/utils/utils.py @@ -19,7 +19,8 @@ def reform_idx(flatten_pred_res, save_pred_res): return re def hamming_dist(A, B): - B = np.array(B) + A = np.array(A, dtype=' Date: Wed, 8 Mar 2023 10:19:00 +0000 Subject: [PATCH 187/601] Update several files --- abl/abducer/abducer_base.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index 61cab25..54dbec1 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -85,7 +85,6 @@ class AbducerBase(abc.ABC): ) parameter = Parameter(budget=100, intermediate_result=False, autoset=True) solution = Opt.min(objective, parameter).get_x() - return solution def address_by_idx(self, pred_res, key, address_idx): @@ -106,7 +105,6 @@ class AbducerBase(abc.ABC): ) candidate = self._get_one_candidate(pred_res, pred_res_prob, candidates) - return candidate def abduce_rules(self, pred_res): From acfc25e2085009aa2f08bfc57e987ae6eb582283 Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Thu, 9 Mar 2023 09:06:50 +0800 Subject: [PATCH 188/601] Update kb.py --- abl/abducer/kb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 2a29d12..370b790 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -17,7 +17,7 @@ import numpy as np from collections import defaultdict from itertools import product, combinations -from utils.utils import flatten, reform_idx, hamming_dist, check_equal +from ..utils.utils import flatten, reform_idx, hamming_dist, check_equal from multiprocessing import Pool From 8e8aa76735eeee73cfc2a026ccddf008f99ea531 Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Thu, 9 Mar 2023 10:54:18 +0800 Subject: [PATCH 189/601] Add cache in abduce_by_search --- abl/abducer/kb.py | 39 ++++++++------------------------------- abl/utils/utils.py | 16 ++++++++++++++-- 2 files changed, 22 insertions(+), 33 deletions(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 370b790..6cecba4 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -17,7 +17,7 @@ import numpy as np from collections import defaultdict from itertools import product, combinations -from ..utils.utils import flatten, reform_idx, hamming_dist, check_equal +from ..utils.utils import flatten, reform_idx, hamming_dist, check_equal, to_hashable, hashable_to_list from multiprocessing import Pool @@ -25,22 +25,17 @@ from functools import lru_cache import pyswip class KBBase(ABC): - def __init__(self, pseudo_label_list, len_list=None, GKB_flag=False, max_err=0):#, abduce_cache=True): + def __init__(self, pseudo_label_list, len_list=None, GKB_flag=False, max_err=0): self.pseudo_label_list = pseudo_label_list self.len_list = len_list self.GKB_flag = GKB_flag self.max_err = max_err - # self.abduce_cache = abduce_cache if GKB_flag: self.base = {} X, Y = self._get_GKB() for x, y in zip(X, Y): self.base.setdefault(len(x), defaultdict(list))[y].append(x) - - # if abduce_cache: - # self.cache_min_address_num = {} - # self.cache_candidates = {} # For parallel version of _get_GKB def _get_XY_list(self, args): @@ -90,7 +85,7 @@ class KBBase(ABC): if self.GKB_flag: return self._abduce_by_GKB(pred_res, key, max_address_num, require_more_address, multiple_predictions) else: - return self._abduce_by_search(pred_res, key, max_address_num, require_more_address, multiple_predictions) + return self._abduce_by_search(to_hashable(pred_res), to_hashable(key), max_address_num, require_more_address, multiple_predictions) @abstractmethod def _find_candidate_GKB(self, pred_res, key): @@ -137,27 +132,7 @@ class KBBase(ABC): idxs = np.where(multiple_cost_list <= address_num)[0] candidates = [reform_idx(multiple_all_candidates[idx], pred_res) for idx in idxs] return candidates - - # TODO:python也有自带的用装饰器实现的缓存方法,比如functools.lru_cacheã€cachetools等,åŽé¢ç¨å¾®è°ƒç ”一下和手动缓存的优劣,看看用哪个好 - # def _get_abduce_cache(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): - # if multiple_predictions: - # pred_res = flatten(pred_res) - # key = tuple(key) - # if (tuple(pred_res), key) in self.cache_min_address_num: - # address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), key)] + require_more_address) - # if (tuple(pred_res), key, address_num) in self.cache_candidates: - # candidates = self.cache_candidates[(tuple(pred_res), key, address_num)] - # return candidates - # return None - - # def _set_abduce_cache(self, pred_res, key, min_address_num, address_num, candidates, multiple_predictions): - # if multiple_predictions: - # pred_res = flatten(pred_res) - # key = tuple(key) - # self.cache_min_address_num[(tuple(pred_res), key)] = min_address_num - # self.cache_candidates[(tuple(pred_res), key, address_num)] = candidates - - + def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): candidates = [] abduce_c = product(self.pseudo_label_list, repeat=len(address_idx)) @@ -190,13 +165,15 @@ class KBBase(ABC): new_candidates += candidates return new_candidates - # @lru_cache(maxsize=100) + @lru_cache(maxsize=100) def _abduce_by_search(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): # if self.abduce_cache: # candidates = self._get_abduce_cache(pred_res, key, max_address_num, require_more_address, multiple_predictions) # if candidates is not None: # return candidates - + pred_res = hashable_to_list(pred_res) + key = hashable_to_list(key) + candidates = [] for address_num in range(len(flatten(pred_res)) + 1): diff --git a/abl/utils/utils.py b/abl/utils/utils.py index d5209a6..90376aa 100644 --- a/abl/utils/utils.py +++ b/abl/utils/utils.py @@ -35,7 +35,6 @@ def confidence_dist(A, B): cols = np.expand_dims(cols, axis = 0).repeat(axis = 0, repeats = len(B)) return 1 - np.prod(A[rows, cols, B], axis = 1) - def block_sample(X, Z, Y, sample_num, epoch_idx): part_num = len(X) // sample_num if part_num == 0: @@ -48,7 +47,6 @@ def block_sample(X, Z, Y, sample_num, epoch_idx): return X, Z, Y - def gen_mappings(chars, symbs): n_char = len(chars) n_symbs = len(symbs) @@ -86,3 +84,17 @@ def check_equal(a, b, max_err=0): else: return a == b + +def to_hashable(l): + if type(l) is not list: + return l + if type(l[0]) is not list: + return tuple(l) + return tuple(tuple(sublist) for sublist in l) + +def hashable_to_list(t): + if type(t) is not tuple: + return t + if type(t[0]) is not tuple: + return list(t) + return [list(subtuple) for subtuple in t] \ No newline at end of file From e735693610fb9cd9568cf8dc64daa96b8ac46772 Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Thu, 9 Mar 2023 13:14:47 +0800 Subject: [PATCH 190/601] Fix a minor bug --- abl/abducer/kb.py | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 6cecba4..333901e 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -113,7 +113,6 @@ class KBBase(ABC): min_address_num = 0 all_candidates_save = [] cost_list_save = [] - for p_res, k in zip(pred_res, key): if len(p_res) not in self.len_list: return [] @@ -136,7 +135,6 @@ class KBBase(ABC): def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): candidates = [] abduce_c = product(self.pseudo_label_list, repeat=len(address_idx)) - if multiple_predictions: save_pred_res = pred_res pred_res = flatten(pred_res) @@ -145,10 +143,8 @@ class KBBase(ABC): candidate = pred_res.copy() for i, idx in enumerate(address_idx): candidate[idx] = c[i] - if multiple_predictions: candidate = reform_idx(candidate, save_pred_res) - if check_equal(self._logic_forward(candidate, multiple_predictions), key, self.max_err): candidates.append(candidate) return candidates @@ -167,15 +163,10 @@ class KBBase(ABC): @lru_cache(maxsize=100) def _abduce_by_search(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): - # if self.abduce_cache: - # candidates = self._get_abduce_cache(pred_res, key, max_address_num, require_more_address, multiple_predictions) - # if candidates is not None: - # return candidates pred_res = hashable_to_list(pred_res) key = hashable_to_list(key) candidates = [] - for address_num in range(len(flatten(pred_res)) + 1): if address_num == 0: if check_equal(self._logic_forward(pred_res, multiple_predictions), key, self.max_err): @@ -183,23 +174,17 @@ class KBBase(ABC): else: new_candidates = self._address(address_num, pred_res, key, multiple_predictions) candidates += new_candidates - if len(candidates) > 0: min_address_num = address_num break - if address_num >= max_address_num: return [] for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): if address_num > max_address_num: - return candidates, min_address_num, address_num - 1 + return candidates new_candidates = self._address(address_num, pred_res, key, multiple_predictions) candidates += new_candidates - - # if self.abduce_cache: - # self._set_abduce_cache(pred_res, key, min_address_num, address_num, candidates, multiple_predictions) - return candidates def _dict_len(self, dic): From 7b209e73a501cf8c761c5a65091988b515651f99 Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Tue, 14 Mar 2023 14:53:30 +0800 Subject: [PATCH 191/601] update TODO in abducer_base --- abl/abducer/abducer_base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index 54dbec1..e2a16bf 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -62,6 +62,7 @@ class AbducerBase(abc.ABC): else: all_address_flag = reform_idx(sol.get_x(), pred_res) score = 0 + # TODO:这个循环里,和上é¢if not self.multiple_predictions部分逻辑完全一样å§ï¼Œåº”该把上é¢å°è£…一下,然åŽä¸‹é¢å¾ªçŽ¯é‡Œè°ƒç”¨å°è£…方法å³å¯ for idx in range(len(pred_res)): address_idx = np.where(all_address_flag[idx] != 0)[0] candidates = self.address_by_idx([pred_res[idx]], key[idx], address_idx) From c5fadfcbb69f1c52cc5926312def088e396cfd5f Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Tue, 14 Mar 2023 15:05:48 +0800 Subject: [PATCH 192/601] Rearrange rules to --- abl/abducer/kb.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 333901e..feba8c4 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -271,12 +271,16 @@ class prolog_KB(KBBase): candidates.append(candidate) return candidates + +class HED_prolog_KB(prolog_KB): + def __init__(self, pseudo_label_list, pl_file): + super().__init__(pseudo_label_list, pl_file) + def consist_rule(self, exs, rules): rules = str(rules).replace("\'","") return len(list(self.prolog.query("eval_inst_feature(%s, %s)." % (exs, rules)))) != 0 def abduce_rules(self, pred_res): - # print(pred_res) prolog_result = list(self.prolog.query("consistent_inst_feature(%s, X)." % pred_res)) if len(prolog_result) == 0: return None From 88a8f33f169fbd6306367609efbf98522252d0b9 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 14 Mar 2023 15:08:13 +0800 Subject: [PATCH 193/601] Add `_get_zoopt_score` --- abl/abducer/abducer_base.py | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index e2a16bf..d52f74b 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -50,26 +50,23 @@ class AbducerBase(abc.ABC): cost_list = self._get_cost_list(pred_res, pred_res_prob, candidates) candidate = candidates[np.argmin(cost_list)] return candidate - + + def _get_zoopt_score(self, sol_x, pred_res, pred_res_prob, key): + address_idx = np.where(sol_x != 0)[0] + candidates = self.address_by_idx(pred_res, key, address_idx) + if len(candidates) > 0: + return np.min(self._get_cost_list(pred_res, pred_res_prob, candidates)) + else: + return len(pred_res) + def _zoopt_address_score(self, pred_res, pred_res_prob, key, sol): if not self.multiple_predictions: - address_idx = np.where(sol.get_x() != 0)[0] - candidates = self.address_by_idx(pred_res, key, address_idx) - if len(candidates) > 0: - return np.min(self._get_cost_list(pred_res, pred_res_prob, candidates)) - else: - return len(pred_res) + return self._get_address_score(sol.get_x(), pred_res, pred_res_prob, key) else: all_address_flag = reform_idx(sol.get_x(), pred_res) score = 0 - # TODO:这个循环里,和上é¢if not self.multiple_predictions部分逻辑完全一样å§ï¼Œåº”该把上é¢å°è£…一下,然åŽä¸‹é¢å¾ªçŽ¯é‡Œè°ƒç”¨å°è£…方法å³å¯ for idx in range(len(pred_res)): - address_idx = np.where(all_address_flag[idx] != 0)[0] - candidates = self.address_by_idx([pred_res[idx]], key[idx], address_idx) - if len(candidates) > 0: - score += np.min(self._get_cost_list(pred_res[idx], pred_res_prob[idx], candidates)) - else: - score += len(pred_res[idx]) + score += self._get_address_score(all_address_flag[idx], pred_res[idx], pred_res_prob[idx], key) return score def _constrain_address_num(self, solution, max_address_num): @@ -112,10 +109,10 @@ class AbducerBase(abc.ABC): return self.kb.abduce_rules(pred_res) def batch_abduce(self, Z, Y, max_address_num=-1, require_more_address=0): - # if self.multiple_predictions: - return self.abduce((Z['cls'], Z['prob'], Y), max_address_num, require_more_address) - # else: - # return [self.abduce((z, prob, y), max_address_num, require_more_address) for z, prob, y in zip(Z['cls'], Z['prob'], Y)] + if self.multiple_predictions: + return self.abduce((Z['cls'], Z['prob'], Y), max_address_num, require_more_address) + else: + return [self.abduce((z, prob, y), max_address_num, require_more_address) for z, prob, y in zip(Z['cls'], Z['prob'], Y)] def __call__(self, Z, Y, max_address_num=-1, require_more_address=0): return self.batch_abduce(Z, Y, max_address_num, require_more_address) @@ -241,4 +238,4 @@ if __name__ == '__main__': print() abduced_rules = abd.abduce_rules(consist_exs) - print(abduced_rules) \ No newline at end of file + print(abduced_rules) From a71af2e5ab4bb953931d15d86f0ab23107f8c0a8 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Tue, 14 Mar 2023 15:08:37 +0800 Subject: [PATCH 194/601] Rearrange rules to `HED_prolog_KB` --- abl/abducer/kb.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 333901e..fb606f3 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -271,12 +271,16 @@ class prolog_KB(KBBase): candidates.append(candidate) return candidates + +class HED_prolog_KB(prolog_KB): + def __init__(self, pseudo_label_list, pl_file): + super().__init__(pseudo_label_list, pl_file) + def consist_rule(self, exs, rules): rules = str(rules).replace("\'","") return len(list(self.prolog.query("eval_inst_feature(%s, %s)." % (exs, rules)))) != 0 def abduce_rules(self, pred_res): - # print(pred_res) prolog_result = list(self.prolog.query("consistent_inst_feature(%s, X)." % pred_res)) if len(prolog_result) == 0: return None @@ -341,4 +345,4 @@ class HWF_KB(RegKB): if __name__ == "__main__": - pass \ No newline at end of file + pass From 176f4bdd20e4dc08479cbf160874d11aeca7cac3 Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Tue, 14 Mar 2023 15:26:35 +0800 Subject: [PATCH 195/601] fix method name bug in abducer_base --- abl/abducer/abducer_base.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index d52f74b..06845a3 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -51,7 +51,7 @@ class AbducerBase(abc.ABC): candidate = candidates[np.argmin(cost_list)] return candidate - def _get_zoopt_score(self, sol_x, pred_res, pred_res_prob, key): + def _zoopt_address_score_single(self, sol_x, pred_res, pred_res_prob, key): address_idx = np.where(sol_x != 0)[0] candidates = self.address_by_idx(pred_res, key, address_idx) if len(candidates) > 0: @@ -61,12 +61,12 @@ class AbducerBase(abc.ABC): def _zoopt_address_score(self, pred_res, pred_res_prob, key, sol): if not self.multiple_predictions: - return self._get_address_score(sol.get_x(), pred_res, pred_res_prob, key) + return self._zoopt_address_score_single(sol.get_x(), pred_res, pred_res_prob, key) else: all_address_flag = reform_idx(sol.get_x(), pred_res) score = 0 for idx in range(len(pred_res)): - score += self._get_address_score(all_address_flag[idx], pred_res[idx], pred_res_prob[idx], key) + score += self._zoopt_address_score_single(all_address_flag[idx], pred_res[idx], pred_res_prob[idx], key) return score def _constrain_address_num(self, solution, max_address_num): From d80e9228d3ac70f08fb3633e16efad71d9a1ccf7 Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Tue, 14 Mar 2023 17:35:40 +0800 Subject: [PATCH 196/601] update TODO in kb --- abl/abducer/kb.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index fb606f3..8bb7854 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -26,6 +26,10 @@ import pyswip class KBBase(ABC): def __init__(self, pseudo_label_list, len_list=None, GKB_flag=False, max_err=0): + # TODO:添加一下类型检查,比如 + # if not isinstance(X, (np.ndarray, spmatrix)): + # raise TypeError("X should be numpy array or sparse matrix") + self.pseudo_label_list = pseudo_label_list self.len_list = len_list self.GKB_flag = GKB_flag @@ -161,6 +165,7 @@ class KBBase(ABC): new_candidates += candidates return new_candidates + # TODO:在类åˆå§‹åŒ–时应该有一个cache(默认Trueï¼‰çš„å‚æ•°ï¼Œç”¨æˆ·å¯ä»¥æŒ‡å®šæ˜¯å¦ç”¨cache(若KB会å˜ï¼Œé‚£ä¸èƒ½ç”¨cache) @lru_cache(maxsize=100) def _abduce_by_search(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): pred_res = hashable_to_list(pred_res) From 2aa88634abacf1a1e419fb50320f45ab40791315 Mon Sep 17 00:00:00 2001 From: Tony-HYX <605698554@qq.com> Date: Tue, 14 Mar 2023 18:06:42 +0800 Subject: [PATCH 197/601] update TODO in kb --- abl/abducer/kb.py | 1 + 1 file changed, 1 insertion(+) diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 8bb7854..fafc1a8 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -166,6 +166,7 @@ class KBBase(ABC): return new_candidates # TODO:在类åˆå§‹åŒ–时应该有一个cache(默认Trueï¼‰çš„å‚æ•°ï¼Œç”¨æˆ·å¯ä»¥æŒ‡å®šæ˜¯å¦ç”¨cache(若KB会å˜ï¼Œé‚£ä¸èƒ½ç”¨cache) + # TODO:如果是multiple_predictions=True,那这个cache几乎ä¸ä¼šå‘½ä¸­å§ï¼Ÿ @lru_cache(maxsize=100) def _abduce_by_search(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): pred_res = hashable_to_list(pred_res) From 87c3ba1b71dbc372bf826cb66ada556f8fda8c38 Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Wed, 15 Mar 2023 14:13:31 +0800 Subject: [PATCH 198/601] Remove --- abl/abducer/abducer_base.py | 226 +++++++++++++++++------------ abl/abducer/kb.py | 102 +++++-------- examples/datasets/hed/learn_add.pl | 2 +- 3 files changed, 168 insertions(+), 162 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index 54dbec1..b7e6526 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -16,27 +16,19 @@ from zoopt import Dimension, Objective, Parameter, Opt from ..utils.utils import confidence_dist, flatten, reform_idx, hamming_dist class AbducerBase(abc.ABC): - def __init__(self, kb, dist_func='hamming', zoopt=False, multiple_predictions=False): + def __init__(self, kb, dist_func='hamming', zoopt=False): self.kb = kb assert dist_func == 'hamming' or dist_func == 'confidence' self.dist_func = dist_func self.zoopt = zoopt - self.multiple_predictions = multiple_predictions if dist_func == 'confidence': self.mapping = dict(zip(self.kb.pseudo_label_list, list(range(len(self.kb.pseudo_label_list))))) def _get_cost_list(self, pred_res, pred_res_prob, candidates): if self.dist_func == 'hamming': - if self.multiple_predictions: - pred_res = flatten(pred_res) - candidates = [flatten(c) for c in candidates] - return hamming_dist(pred_res, candidates) elif self.dist_func == 'confidence': - if self.multiple_predictions: - pred_res_prob = flatten(pred_res_prob) - candidates = [flatten(c) for c in candidates] candidates = [list(map(lambda x: self.mapping[x], c)) for c in candidates] return confidence_dist(pred_res_prob, candidates) @@ -50,26 +42,24 @@ class AbducerBase(abc.ABC): cost_list = self._get_cost_list(pred_res, pred_res_prob, candidates) candidate = candidates[np.argmin(cost_list)] return candidate - - def _zoopt_address_score(self, pred_res, pred_res_prob, key, sol): - if not self.multiple_predictions: - address_idx = np.where(sol.get_x() != 0)[0] - candidates = self.address_by_idx(pred_res, key, address_idx) - if len(candidates) > 0: - return np.min(self._get_cost_list(pred_res, pred_res_prob, candidates)) - else: - return len(pred_res) + + def _zoopt_address_score_single(self, sol_x, pred_res, pred_res_prob, key): + address_idx = np.where(sol_x != 0)[0] + candidates = self.address_by_idx(pred_res, key, address_idx) + if len(candidates) > 0: + return np.min(self._get_cost_list(pred_res, pred_res_prob, candidates)) else: - all_address_flag = reform_idx(sol.get_x(), pred_res) - score = 0 - for idx in range(len(pred_res)): - address_idx = np.where(all_address_flag[idx] != 0)[0] - candidates = self.address_by_idx([pred_res[idx]], key[idx], address_idx) - if len(candidates) > 0: - score += np.min(self._get_cost_list(pred_res[idx], pred_res_prob[idx], candidates)) - else: - score += len(pred_res[idx]) - return score + return len(pred_res) + + def _zoopt_address_score(self, pred_res, pred_res_prob, key, sol): + # if not self.multiple_predictions: + return self._zoopt_address_score_single(sol.get_x(), pred_res, pred_res_prob, key) + # else: + # all_address_flag = reform_idx(sol.get_x(), pred_res) + # score = 0 + # for idx in range(len(pred_res)): + # score += self._zoopt_address_score_single(all_address_flag[idx], pred_res[idx], pred_res_prob[idx], key) + # return score def _constrain_address_num(self, solution, max_address_num): x = solution.get_x() @@ -88,21 +78,29 @@ class AbducerBase(abc.ABC): return solution def address_by_idx(self, pred_res, key, address_idx): - return self.kb.address_by_idx(pred_res, key, address_idx, self.multiple_predictions) + return self.kb.address_by_idx(pred_res, key, address_idx) - def abduce(self, data, max_address_num=-1, require_more_address=0): + def abduce(self, data, max_address=-1, require_more_address=0): pred_res, pred_res_prob, key = data - if max_address_num == -1: - max_address_num = len(flatten(pred_res)) + # if max_address_num == -1: + # max_address_num = len(flatten(pred_res)) + + assert(type(max_address) in (int, float)) + if max_address == -1: + max_address_num = len(pred_res) + elif type(max_address) == float: + assert(max_address >= 0 and max_address <= 1) + max_address_num = round(len(pred_res) * max_address) + else: + assert(max_address >= 0) + max_address_num = max_address if self.zoopt: solution = self.zoopt_get_solution(pred_res, pred_res_prob, key, max_address_num) address_idx = np.where(solution != 0)[0] candidates = self.address_by_idx(pred_res, key, address_idx) else: - candidates = self.kb.abduce_candidates( - pred_res, key, max_address_num, require_more_address, self.multiple_predictions - ) + candidates = self.kb.abduce_candidates(pred_res, key, max_address_num, require_more_address) candidate = self._get_one_candidate(pred_res, pred_res_prob, candidates) return candidate @@ -110,134 +108,170 @@ class AbducerBase(abc.ABC): def abduce_rules(self, pred_res): return self.kb.abduce_rules(pred_res) - def batch_abduce(self, Z, Y, max_address_num=-1, require_more_address=0): - # if self.multiple_predictions: - return self.abduce((Z['cls'], Z['prob'], Y), max_address_num, require_more_address) - # else: - # return [self.abduce((z, prob, y), max_address_num, require_more_address) for z, prob, y in zip(Z['cls'], Z['prob'], Y)] + def batch_abduce(self, data, max_address=-1, require_more_address=0): + Z1, Z2, Y = data + return [self.abduce((z, prob, y), max_address, require_more_address) for z, prob, y in zip(Z1, Z2, Y)] def __call__(self, Z, Y, max_address_num=-1, require_more_address=0): return self.batch_abduce(Z, Y, max_address_num, require_more_address) if __name__ == '__main__': - from kb import add_KB, prolog_KB, HWF_KB + from kb import add_KB, prolog_KB, HWF_KB, HED_prolog_KB - prob1 = [[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] - prob2 = [[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] + prob1 = [[[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]] + prob2 = [[[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]] + print('add_KB with GKB:') kb = add_KB(GKB_flag=True) abd = AbducerBase(kb, 'confidence') - res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) + res = abd.batch_abduce(([[1, 1]], prob1, [8]), max_address=2, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob2, 8), max_address_num=2, require_more_address=0) + res = abd.batch_abduce(([[1, 1]], prob2, [8]), max_address=2, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob1, 17), max_address_num=2, require_more_address=0) + res = abd.batch_abduce(([[1, 1]], prob1, [17]), max_address=2, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob1, 17), max_address_num=1, require_more_address=0) + res = abd.batch_abduce(([[1, 1]], prob1, [17]), max_address=1, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob1, 20), max_address_num=2, require_more_address=0) + res = abd.batch_abduce(([[1, 1]], prob1, [20]), max_address=2, require_more_address=0) print(res) print() - - multiple_prob = [[[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]], - [[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]] - - + print('add_KB without GKB:') kb = add_KB() - abd = AbducerBase(kb, 'confidence', multiple_predictions=True) - res = abd.abduce(([[1, 1], [1, 2]], multiple_prob, [4, 8]), max_address_num=4, require_more_address=0) + abd = AbducerBase(kb, 'confidence') + res = abd.batch_abduce(([[1, 1]], prob1, [8]), max_address=2, require_more_address=0) + print(res) + res = abd.batch_abduce(([[1, 1]], prob2, [8]), max_address=2, require_more_address=0) print(res) - res = abd.abduce(([[1, 1], [1, 2]], multiple_prob, [4, 8]), max_address_num=4, require_more_address=1) + res = abd.batch_abduce(([[1, 1]], prob1, [17]), max_address=2, require_more_address=0) + print(res) + res = abd.batch_abduce(([[1, 1]], prob1, [17]), max_address=1, require_more_address=0) + print(res) + res = abd.batch_abduce(([[1, 1]], prob1, [20]), max_address=2, require_more_address=0) print(res) print() - + print('prolog_KB with add.pl:') kb = prolog_KB(pseudo_label_list=list(range(10)), pl_file='../examples/datasets/mnist_add/add.pl') abd = AbducerBase(kb, 'confidence') - res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) + res = abd.batch_abduce(([[1, 1]], prob1, [8]), max_address=2, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob2, 8), max_address_num=2, require_more_address=0) + res = abd.batch_abduce(([[1, 1]], prob2, [8]), max_address=2, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob1, 17), max_address_num=2, require_more_address=0) + res = abd.batch_abduce(([[1, 1]], prob1, [17]), max_address=2, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob1, 17), max_address_num=1, require_more_address=0) + res = abd.batch_abduce(([[1, 1]], prob1, [17]), max_address=1, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob1, 20), max_address_num=2, require_more_address=0) + res = abd.batch_abduce(([[1, 1]], prob1, [20]), max_address=2, require_more_address=0) print(res) print() + print('prolog_KB with add.pl using zoopt:') kb = prolog_KB(pseudo_label_list=list(range(10)), pl_file='../examples/datasets/mnist_add/add.pl') abd = AbducerBase(kb, 'confidence', zoopt=True) - res = abd.abduce(([1, 1], prob1, 8), max_address_num=2, require_more_address=0) + res = abd.batch_abduce(([[1, 1]], prob1, [8]), max_address=2, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob2, 8), max_address_num=2, require_more_address=0) + res = abd.batch_abduce(([[1, 1]], prob2, [8]), max_address=2, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob1, 17), max_address_num=2, require_more_address=0) + res = abd.batch_abduce(([[1, 1]], prob1, [17]), max_address=2, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob1, 17), max_address_num=1, require_more_address=0) + res = abd.batch_abduce(([[1, 1]], prob1, [17]), max_address=1, require_more_address=0) print(res) - res = abd.abduce(([1, 1], prob1, 20), max_address_num=2, require_more_address=0) + res = abd.batch_abduce(([[1, 1]], prob1, [20]), max_address=2, require_more_address=0) print(res) print() - - kb = HWF_KB(len_list=[1, 3, 5], GKB_flag=True, max_err = 0.1) - abd = AbducerBase(kb, 'hamming') - res = abd.abduce((['5', '+', '2'], None, 3), max_address_num=2, require_more_address=0) + + print('add_KB with multiple inputs at once:') + multiple_prob = [[[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]], + [[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]] + + kb = add_KB() + abd = AbducerBase(kb, 'confidence') + res = abd.batch_abduce(([[1, 1], [1, 2]], multiple_prob, [4, 8]), max_address=4, require_more_address=0) print(res) - res = abd.abduce((['5', '+', '9'], None, 64), max_address_num=3, require_more_address=0) + res = abd.batch_abduce(([[1, 1], [1, 2]], multiple_prob, [4, 8]), max_address=4, require_more_address=1) print(res) print() - kb = HWF_KB(len_list=[1, 3, 5], GKB_flag=True, max_err = 1) + print('HWF_KB with GKB, max_err=0.1') + kb = HWF_KB(len_list=[1, 3, 5], GKB_flag=True, max_err = 0.1) abd = AbducerBase(kb, 'hamming') - res = abd.abduce((['5', '+', '9'], None, 64), max_address_num=3, require_more_address=0) + res = abd.batch_abduce(([['5', '+', '2']], [None], [3]), max_address=2, require_more_address=0) print(res) - res = abd.abduce((['5', '+', '2'], None, 1.67), max_address_num=3, require_more_address=0) + res = abd.batch_abduce(([['5', '+', '9']], [None], [65]), max_address=3, require_more_address=0) print(res) - res = abd.abduce((['5', '8', '8', '8', '8'], None, 3.17), max_address_num=5, require_more_address=3) + res = abd.batch_abduce(([['5', '8', '8', '8', '8']], [None], [3.17]), max_address=5, require_more_address=3) print(res) print() + print('HWF_KB without GKB, max_err=0.1') kb = HWF_KB(len_list=[1, 3, 5], max_err = 0.1) - abd = AbducerBase(kb, 'hamming', multiple_predictions=True) - res = abd.abduce(([['5', '+', '2'], ['5', '+', '9']], None, [3, 64]), max_address_num=6, require_more_address=0) + abd = AbducerBase(kb, 'hamming') + res = abd.batch_abduce(([['5', '+', '2']], [None], [3]), max_address=2, require_more_address=0) + print(res) + res = abd.batch_abduce(([['5', '+', '9']], [None], [65]), max_address=3, require_more_address=0) + print(res) + res = abd.batch_abduce(([['5', '8', '8', '8', '8']], [None], [3.17]), max_address=5, require_more_address=3) print(res) print() - kb = HWF_KB(len_list=[1, 3, 5], max_err = 0.1) + print('HWF_KB with GKB, max_err=1') + kb = HWF_KB(len_list=[1, 3, 5], GKB_flag=True, max_err = 1) abd = AbducerBase(kb, 'hamming') - res = abd.abduce((['5', '+', '2'], None, 3), max_address_num=2, require_more_address=0) + res = abd.batch_abduce(([['5', '+', '9']], [None], [65]), max_address=3, require_more_address=0) print(res) - res = abd.abduce((['5', '+', '9'], None, 64), max_address_num=3, require_more_address=0) + res = abd.batch_abduce(([['5', '+', '2']], [None], [1.67]), max_address=3, require_more_address=0) print(res) + res = abd.batch_abduce(([['5', '8', '8', '8', '8']], [None], [3.17]), max_address=5, require_more_address=3) + print(res) + print() + print('HWF_KB without GKB, max_err=1') kb = HWF_KB(len_list=[1, 3, 5], max_err = 1) abd = AbducerBase(kb, 'hamming') - res = abd.abduce((['5', '+', '9'], None, 64), max_address_num=3, require_more_address=0) + res = abd.batch_abduce(([['5', '+', '9']], [None], [65]), max_address=3, require_more_address=0) + print(res) + res = abd.batch_abduce(([['5', '+', '2']], [None], [1.67]), max_address=3, require_more_address=0) + print(res) + res = abd.batch_abduce(([['5', '8', '8', '8', '8']], [None], [3.17]), max_address=5, require_more_address=3) + print(res) + print() + + print('HWF_KB with multiple inputs at once:') + kb = HWF_KB(len_list=[1, 3, 5], max_err = 0.1) + abd = AbducerBase(kb, 'hamming') + res = abd.batch_abduce(([['5', '+', '2'], ['5', '+', '9']], [None, None], [3, 64]), max_address=1, require_more_address=0) print(res) - res = abd.abduce((['5', '+', '2'], None, 1.67), max_address_num=3, require_more_address=0) + res = abd.batch_abduce(([['5', '+', '2'], ['5', '+', '9']], [None, None], [3, 64]), max_address=3, require_more_address=0) print(res) - res = abd.abduce((['5', '8', '8', '8', '8'], None, 3.17), max_address_num=5, require_more_address=3) + res = abd.batch_abduce(([['5', '+', '2'], ['5', '+', '9']], [None, None], [3, 65]), max_address=3, require_more_address=0) + print(res) + print() + print('max_address is float') + res = abd.batch_abduce(([['5', '+', '2'], ['5', '+', '9']], [None, None], [3, 64]), max_address=0.5, require_more_address=0) + print(res) + res = abd.batch_abduce(([['5', '+', '2'], ['5', '+', '9']], [None, None], [3, 64]), max_address=0.9, require_more_address=0) print(res) print() - kb = prolog_KB(pseudo_label_list=[1, 0, '+', '='], pl_file='../examples/datasets/hed/learn_add.pl') - abd = AbducerBase(kb, zoopt=True, multiple_predictions=True) + kb = HED_prolog_KB(pseudo_label_list=[1, 0, '+', '='], pl_file='../examples/datasets/hed/learn_add.pl') + abd = AbducerBase(kb, zoopt=True) consist_exs = [[1, 1, '+', 0, '=', 1, 1], [1, '+', 1, '=', 1, 0], [0, '+', 0, '=', 0]] inconsist_exs = [[1, '+', 0, '=', 0], [1, '=', 1, '=', 0], [0, '=', 0, '=', 1, 1]] - # inconsist_exs = [[1, '+', 0, '=', 0], ['=', '=', '=', '=', 0], ['=', '=', 0, '=', '=', '=']] rules = ['my_op([0], [0], [0])', 'my_op([1], [1], [1, 0])'] - print(kb._logic_forward(consist_exs, True), kb._logic_forward(inconsist_exs, True)) - print(kb.consist_rule([1, '+', 1, '=', 1, 0], rules), kb.consist_rule([1, '+', 1, '=', 1, 1], rules)) + print(kb.logic_forward(consist_exs)) + print(kb.logic_forward(inconsist_exs)) print() - - res = abd.abduce((consist_exs, [None] * len(consist_exs), [None] * len(consist_exs))) - print(res) - res = abd.abduce((inconsist_exs, [None] * len(consist_exs), [None] * len(inconsist_exs))) - print(res) + print(kb.consist_rule([1, '+', 1, '=', 1, 0], rules)) + print(kb.consist_rule([1, '+', 1, '=', 1, 1], rules)) print() - abduced_rules = abd.abduce_rules(consist_exs) - print(abduced_rules) \ No newline at end of file + # res = abd.abduce((consist_exs, [None] * len(consist_exs), [None] * len(consist_exs))) + # print(res) + # res = abd.batch_abduce((inconsist_exs, [None] * len(consist_exs), [None] * len(inconsist_exs))) + # print(res) + # print() + + # abduced_rules = abd.batch_abduce_rules(consist_exs) + # print(abduced_rules) \ No newline at end of file diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index feba8c4..42a5f6c 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -17,7 +17,7 @@ import numpy as np from collections import defaultdict from itertools import product, combinations -from ..utils.utils import flatten, reform_idx, hamming_dist, check_equal, to_hashable, hashable_to_list +from utils.utils import flatten, reform_idx, hamming_dist, check_equal, to_hashable, hashable_to_list from multiprocessing import Pool @@ -25,11 +25,16 @@ from functools import lru_cache import pyswip class KBBase(ABC): - def __init__(self, pseudo_label_list, len_list=None, GKB_flag=False, max_err=0): + def __init__(self, pseudo_label_list, len_list=None, GKB_flag=False, max_err=0, cache_size=128): + # TODO:添加一下类型检查,比如 + # if not isinstance(X, (np.ndarray, spmatrix)): + # raise TypeError("X should be numpy array or sparse matrix") + self.pseudo_label_list = pseudo_label_list self.len_list = len_list self.GKB_flag = GKB_flag self.max_err = max_err + self.cache_size = cache_size if GKB_flag: self.base = {} @@ -73,106 +78,73 @@ class KBBase(ABC): @abstractmethod def logic_forward(self, pseudo_labels): pass - - def _logic_forward(self, xs, multiple_predictions=False): - if not multiple_predictions: - return self.logic_forward(xs) - else: - res = [self.logic_forward(x) for x in xs] - return res - def abduce_candidates(self, pred_res, key, max_address_num, require_more_address=0, multiple_predictions=False): + def abduce_candidates(self, pred_res, key, max_address_num, require_more_address=0): if self.GKB_flag: - return self._abduce_by_GKB(pred_res, key, max_address_num, require_more_address, multiple_predictions) + return self._abduce_by_GKB(pred_res, key, max_address_num, require_more_address) else: - return self._abduce_by_search(to_hashable(pred_res), to_hashable(key), max_address_num, require_more_address, multiple_predictions) + return self._abduce_by_search(to_hashable(pred_res), to_hashable(key), max_address_num, require_more_address) @abstractmethod def _find_candidate_GKB(self, pred_res, key): pass - def _abduce_by_GKB(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): + def _abduce_by_GKB(self, pred_res, key, max_address_num, require_more_address): if self.base == {}: return [] - - if not multiple_predictions: - if len(pred_res) not in self.len_list: - return [] - all_candidates = self._find_candidate_GKB(pred_res, key) - if len(all_candidates) == 0: - return [] - else: - cost_list = hamming_dist(pred_res, all_candidates) - min_address_num = np.min(cost_list) - address_num = min(max_address_num, min_address_num + require_more_address) - idxs = np.where(cost_list <= address_num)[0] - candidates = [all_candidates[idx] for idx in idxs] - return candidates - + + if len(pred_res) not in self.len_list: + return [] + all_candidates = self._find_candidate_GKB(pred_res, key) + if len(all_candidates) == 0: + return [] else: - min_address_num = 0 - all_candidates_save = [] - cost_list_save = [] - for p_res, k in zip(pred_res, key): - if len(p_res) not in self.len_list: - return [] - all_candidates = self._find_candidate_GKB(p_res, k) - if len(all_candidates) == 0: - return [] - else: - all_candidates_save.append(all_candidates) - cost_list = hamming_dist(p_res, all_candidates) - min_address_num += np.min(cost_list) - cost_list_save.append(cost_list) - - multiple_all_candidates = [flatten(c) for c in product(*all_candidates_save)] - multiple_cost_list = np.array([sum(cost) for cost in product(*cost_list_save)]) + cost_list = hamming_dist(pred_res, all_candidates) + min_address_num = np.min(cost_list) address_num = min(max_address_num, min_address_num + require_more_address) - idxs = np.where(multiple_cost_list <= address_num)[0] - candidates = [reform_idx(multiple_all_candidates[idx], pred_res) for idx in idxs] + idxs = np.where(cost_list <= address_num)[0] + candidates = [all_candidates[idx] for idx in idxs] return candidates - def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): + def address_by_idx(self, pred_res, key, address_idx): candidates = [] abduce_c = product(self.pseudo_label_list, repeat=len(address_idx)) - if multiple_predictions: - save_pred_res = pred_res - pred_res = flatten(pred_res) + # if multiple_predictions: + # save_pred_res = pred_res + # pred_res = flatten(pred_res) for c in abduce_c: candidate = pred_res.copy() for i, idx in enumerate(address_idx): candidate[idx] = c[i] - if multiple_predictions: - candidate = reform_idx(candidate, save_pred_res) - if check_equal(self._logic_forward(candidate, multiple_predictions), key, self.max_err): + # if multiple_predictions: + # candidate = reform_idx(candidate, save_pred_res) + if check_equal(self.logic_forward(candidate), key, self.max_err): candidates.append(candidate) return candidates - def _address(self, address_num, pred_res, key, multiple_predictions): + def _address(self, address_num, pred_res, key): new_candidates = [] - if not multiple_predictions: - address_idx_list = combinations(list(range(len(pred_res))), address_num) - else: - address_idx_list = combinations(list(range(len(flatten(pred_res)))), address_num) + address_idx_list = combinations(list(range(len(pred_res))), address_num) for address_idx in address_idx_list: - candidates = self.address_by_idx(pred_res, key, address_idx, multiple_predictions) + candidates = self.address_by_idx(pred_res, key, address_idx) new_candidates += candidates return new_candidates - @lru_cache(maxsize=100) - def _abduce_by_search(self, pred_res, key, max_address_num, require_more_address, multiple_predictions): + # TODO:在类åˆå§‹åŒ–时应该有一个cache(默认Trueï¼‰çš„å‚æ•°ï¼Œç”¨æˆ·å¯ä»¥æŒ‡å®šæ˜¯å¦ç”¨cache(若KB会å˜ï¼Œé‚£ä¸èƒ½ç”¨cache) + @lru_cache(maxsize=None) + def _abduce_by_search(self, pred_res, key, max_address_num, require_more_address): pred_res = hashable_to_list(pred_res) key = hashable_to_list(key) candidates = [] for address_num in range(len(flatten(pred_res)) + 1): if address_num == 0: - if check_equal(self._logic_forward(pred_res, multiple_predictions), key, self.max_err): + if check_equal(self.logic_forward(pred_res), key, self.max_err): candidates.append(pred_res) else: - new_candidates = self._address(address_num, pred_res, key, multiple_predictions) + new_candidates = self._address(address_num, pred_res, key) candidates += new_candidates if len(candidates) > 0: min_address_num = address_num @@ -183,7 +155,7 @@ class KBBase(ABC): for address_num in range(min_address_num + 1, min_address_num + require_more_address + 1): if address_num > max_address_num: return candidates - new_candidates = self._address(address_num, pred_res, key, multiple_predictions) + new_candidates = self._address(address_num, pred_res, key) candidates += new_candidates return candidates diff --git a/examples/datasets/hed/learn_add.pl b/examples/datasets/hed/learn_add.pl index fbf698f..35a71c6 100644 --- a/examples/datasets/hed/learn_add.pl +++ b/examples/datasets/hed/learn_add.pl @@ -32,7 +32,7 @@ abduce_consistent_insts(Exs):- % (Experimental) Uncomment to use parallel abduction % abduce_consistent_exs_concurrent(Exs), !. -logic_forward(Exs, X) :- abduce_consistent_insts([Exs]) -> X = true ; X = false. +logic_forward(Exs, X) :- abduce_consistent_insts(Exs) -> X = true ; X = false. logic_forward(Exs) :- abduce_consistent_insts(Exs). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% From b49fb76f0e004e79c968b4767fa15d790c10aee0 Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Wed, 15 Mar 2023 14:33:21 +0800 Subject: [PATCH 199/601] Remove --- abl/abducer/abducer_base.py | 5 +---- abl/abducer/kb.py | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index c5527f9..b7e6526 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -10,13 +10,10 @@ # # ================================================================# -import sys -sys.path.append('/home/huwc/ABL-Package/abl/') - import abc import numpy as np from zoopt import Dimension, Objective, Parameter, Opt -from utils.utils import confidence_dist, flatten, reform_idx, hamming_dist +from ..utils.utils import confidence_dist, flatten, reform_idx, hamming_dist class AbducerBase(abc.ABC): def __init__(self, kb, dist_func='hamming', zoopt=False): diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index 42a5f6c..f7d8091 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -17,7 +17,7 @@ import numpy as np from collections import defaultdict from itertools import product, combinations -from utils.utils import flatten, reform_idx, hamming_dist, check_equal, to_hashable, hashable_to_list +from ..utils.utils import flatten, reform_idx, hamming_dist, check_equal, to_hashable, hashable_to_list from multiprocessing import Pool From f9dee56b548d67aaae53de38e667fdf50d0185e7 Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Wed, 15 Mar 2023 16:18:19 +0800 Subject: [PATCH 200/601] Update abduce for HED --- abl/abducer/abducer_base.py | 39 ++++++++++++++++++------------------- abl/abducer/kb.py | 32 +++++++++++------------------- abl/utils/utils.py | 10 ++++++++-- 3 files changed, 38 insertions(+), 43 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index b7e6526..620a4ce 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -13,7 +13,7 @@ import abc import numpy as np from zoopt import Dimension, Objective, Parameter, Opt -from ..utils.utils import confidence_dist, flatten, reform_idx, hamming_dist +from ..utils.utils import confidence_dist, flatten, reform_idx, hamming_dist, nested_length class AbducerBase(abc.ABC): def __init__(self, kb, dist_func='hamming', zoopt=False): @@ -52,14 +52,14 @@ class AbducerBase(abc.ABC): return len(pred_res) def _zoopt_address_score(self, pred_res, pred_res_prob, key, sol): - # if not self.multiple_predictions: - return self._zoopt_address_score_single(sol.get_x(), pred_res, pred_res_prob, key) - # else: - # all_address_flag = reform_idx(sol.get_x(), pred_res) - # score = 0 - # for idx in range(len(pred_res)): - # score += self._zoopt_address_score_single(all_address_flag[idx], pred_res[idx], pred_res_prob[idx], key) - # return score + all_address_flag = reform_idx(sol.get_x(), pred_res) + if nested_length(pred_res) == 1: + return self._zoopt_address_score_single(all_address_flag[idx], pred_res, pred_res_prob, key) + else: + score = 0 + for idx in range(nested_length(pred_res)): + score += self._zoopt_address_score_single(all_address_flag[idx], [pred_res[idx]], [pred_res_prob[idx]], [key[idx]]) + return score def _constrain_address_num(self, solution, max_address_num): x = solution.get_x() @@ -78,19 +78,18 @@ class AbducerBase(abc.ABC): return solution def address_by_idx(self, pred_res, key, address_idx): + # print(pred_res, address_idx) return self.kb.address_by_idx(pred_res, key, address_idx) def abduce(self, data, max_address=-1, require_more_address=0): pred_res, pred_res_prob, key = data - # if max_address_num == -1: - # max_address_num = len(flatten(pred_res)) assert(type(max_address) in (int, float)) if max_address == -1: - max_address_num = len(pred_res) + max_address_num = len(flatten(pred_res)) elif type(max_address) == float: assert(max_address >= 0 and max_address <= 1) - max_address_num = round(len(pred_res) * max_address) + max_address_num = round(len(flatten(pred_res)) * max_address) else: assert(max_address >= 0) max_address_num = max_address @@ -267,11 +266,11 @@ if __name__ == '__main__': print(kb.consist_rule([1, '+', 1, '=', 1, 1], rules)) print() - # res = abd.abduce((consist_exs, [None] * len(consist_exs), [None] * len(consist_exs))) - # print(res) - # res = abd.batch_abduce((inconsist_exs, [None] * len(consist_exs), [None] * len(inconsist_exs))) - # print(res) - # print() + res = abd.abduce((consist_exs, [[[None]]] * len(consist_exs), [None] * len(consist_exs))) + print(res) + res = abd.abduce((inconsist_exs, [[[None]]] * len(consist_exs), [None] * len(inconsist_exs))) + print(res) + print() - # abduced_rules = abd.batch_abduce_rules(consist_exs) - # print(abduced_rules) \ No newline at end of file + abduced_rules = abd.abduce_rules(consist_exs) + print(abduced_rules) \ No newline at end of file diff --git a/abl/abducer/kb.py b/abl/abducer/kb.py index f7d8091..1421a97 100644 --- a/abl/abducer/kb.py +++ b/abl/abducer/kb.py @@ -109,16 +109,10 @@ class KBBase(ABC): def address_by_idx(self, pred_res, key, address_idx): candidates = [] abduce_c = product(self.pseudo_label_list, repeat=len(address_idx)) - # if multiple_predictions: - # save_pred_res = pred_res - # pred_res = flatten(pred_res) - for c in abduce_c: candidate = pred_res.copy() for i, idx in enumerate(address_idx): candidate[idx] = c[i] - # if multiple_predictions: - # candidate = reform_idx(candidate, save_pred_res) if check_equal(self.logic_forward(candidate), key, self.max_err): candidates.append(candidate) return candidates @@ -139,7 +133,7 @@ class KBBase(ABC): key = hashable_to_list(key) candidates = [] - for address_num in range(len(flatten(pred_res)) + 1): + for address_num in range(len(pred_res) + 1): if address_num == 0: if check_equal(self.logic_forward(pred_res), key, self.max_err): candidates.append(pred_res) @@ -202,24 +196,22 @@ class prolog_KB(KBBase): return False return result - def _address_pred_res(self, pred_res, address_idx, multiple_predictions): + def _address_pred_res(self, pred_res, address_idx): import re address_pred_res = pred_res.copy() - if multiple_predictions: - address_pred_res = flatten(address_pred_res) + address_pred_res = flatten(address_pred_res) for idx in address_idx: address_pred_res[idx] = 'P' + str(idx) - if multiple_predictions: - address_pred_res = reform_idx(address_pred_res, pred_res) + address_pred_res = reform_idx(address_pred_res, pred_res) # TODO:ä¸çŸ¥é“有没有更简æ´çš„æ–¹æ³• regex = r"'P\d+'" return re.sub(regex, lambda x: x.group().replace("'", ""), str(address_pred_res)) - def get_query_string(self, pred_res, key, address_idx, multiple_predictions): + def get_query_string(self, pred_res, key, address_idx): query_string = "logic_forward(" - query_string += self._address_pred_res(pred_res, address_idx, multiple_predictions) + query_string += self._address_pred_res(pred_res, address_idx) key_is_none_flag = key is None or (type(key) == list and key[0] is None) query_string += ",%s)." % key if not key_is_none_flag else ")." return query_string @@ -227,19 +219,17 @@ class prolog_KB(KBBase): def _find_candidate_GKB(self, pred_res, key): pass - def address_by_idx(self, pred_res, key, address_idx, multiple_predictions=False): + def address_by_idx(self, pred_res, key, address_idx): candidates = [] - query_string = self.get_query_string(pred_res, key, address_idx, multiple_predictions) - if multiple_predictions: - save_pred_res = pred_res - pred_res = flatten(pred_res) + query_string = self.get_query_string(pred_res, key, address_idx) + save_pred_res = pred_res + pred_res = flatten(pred_res) abduce_c = [list(z.values()) for z in self.prolog.query(query_string)] for c in abduce_c: candidate = pred_res.copy() for i, idx in enumerate(address_idx): candidate[idx] = c[i] - if multiple_predictions: - candidate = reform_idx(candidate, save_pred_res) + candidate = reform_idx(candidate, save_pred_res) candidates.append(candidate) return candidates diff --git a/abl/utils/utils.py b/abl/utils/utils.py index 90376aa..a0d5cd1 100644 --- a/abl/utils/utils.py +++ b/abl/utils/utils.py @@ -3,14 +3,20 @@ from .plog import INFO from collections import OrderedDict from itertools import chain -# for multiple predictions +def nested_length(l): + if not isinstance(l[0], (list, tuple)): + return 1 + return len(l) + def flatten(l): if not isinstance(l[0], (list, tuple)): return l return list(chain.from_iterable(l)) -# for multiple predictions def reform_idx(flatten_pred_res, save_pred_res): + if not isinstance(save_pred_res[0], (list, tuple)): + return flatten_pred_res + re = [] i = 0 for e in save_pred_res: From 5d633ff86bb0283076b46d2b13ee274764c6457f Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 15 Mar 2023 16:21:06 +0800 Subject: [PATCH 201/601] Update abducer_base.py --- abl/abducer/abducer_base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index 620a4ce..15f989b 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -54,7 +54,7 @@ class AbducerBase(abc.ABC): def _zoopt_address_score(self, pred_res, pred_res_prob, key, sol): all_address_flag = reform_idx(sol.get_x(), pred_res) if nested_length(pred_res) == 1: - return self._zoopt_address_score_single(all_address_flag[idx], pred_res, pred_res_prob, key) + return self._zoopt_address_score_single(all_address_flag, pred_res, pred_res_prob, key) else: score = 0 for idx in range(nested_length(pred_res)): @@ -273,4 +273,4 @@ if __name__ == '__main__': print() abduced_rules = abd.abduce_rules(consist_exs) - print(abduced_rules) \ No newline at end of file + print(abduced_rules) From 7bccd9ca6eb304597d5cc30bcc1855b65849be56 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Wed, 15 Mar 2023 18:36:27 +0800 Subject: [PATCH 202/601] zoopt_score in ABL-HED --- abl/abducer/abducer_base.py | 47 +++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index 15f989b..d33a7e6 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -52,13 +52,52 @@ class AbducerBase(abc.ABC): return len(pred_res) def _zoopt_address_score(self, pred_res, pred_res_prob, key, sol): - all_address_flag = reform_idx(sol.get_x(), pred_res) if nested_length(pred_res) == 1: - return self._zoopt_address_score_single(all_address_flag, pred_res, pred_res_prob, key) + return self._zoopt_address_score_single(sol.get_x(), pred_res, pred_res_prob, key) else: + all_address_flag = reform_idx(sol.get_x(), pred_res) + lefted_idx = [i for i in range(len(pred_res))] + candidate_size = [] + while lefted_idx: + temp_idx = [] + temp_idx.append(lefted_idx.pop(0)) + max_candidate_idx = [] + found = False + for idx in range(-1, len(pred_res)): + if (not idx in temp_idx) and (idx >= 0): + temp_idx.append(idx) + + pred = [] + k = [] + address_flag = [] + for idx in temp_idx: + pred.append(pred_res[idx]) + k.append(key[idx]) + address_flag += list(all_address_flag[idx]) + address_idx = np.where(np.array(address_flag) != 0)[0] + candidate = self.address_by_idx(pred, k, address_idx) + if len(candidate) == 0: + if len(temp_idx) > 1: + temp_idx.pop() + else: + if len(temp_idx) > len(max_candidate_idx): + found = True + max_candidate_idx = temp_idx.copy() + removed = [i for i in lefted_idx if i in max_candidate_idx] + + if found: + candidate_size.append(len(removed) + 1) + lefted_idx = [i for i in lefted_idx if i not in max_candidate_idx] + + candidate_size.sort() score = 0 - for idx in range(nested_length(pred_res)): - score += self._zoopt_address_score_single(all_address_flag[idx], [pred_res[idx]], [pred_res_prob[idx]], [key[idx]]) + import math + for i in range(0, len(candidate_size)): + score -= math.exp(-i) * candidate_size[i] + + # score = 0 + # for idx in range(nested_length(pred_res)): + # score += self._zoopt_address_score_single(all_address_flag[idx], [pred_res[idx]], [pred_res_prob[idx]], [key[idx]]) return score def _constrain_address_num(self, solution, max_address_num): From 895b9e4290354309c0f5f015e388506f361e1c31 Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Thu, 16 Mar 2023 09:00:41 +0800 Subject: [PATCH 203/601] add HED_Abducer --- abl/abducer/abducer_base.py | 118 +++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 54 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index d33a7e6..b7edd4c 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -10,10 +10,13 @@ # # ================================================================# +import sys +sys.path.append('/home/huwc/ABL-Package/abl') + import abc import numpy as np from zoopt import Dimension, Objective, Parameter, Opt -from ..utils.utils import confidence_dist, flatten, reform_idx, hamming_dist, nested_length +from utils.utils import confidence_dist, flatten, reform_idx, hamming_dist class AbducerBase(abc.ABC): def __init__(self, kb, dist_func='hamming', zoopt=False): @@ -52,53 +55,12 @@ class AbducerBase(abc.ABC): return len(pred_res) def _zoopt_address_score(self, pred_res, pred_res_prob, key, sol): - if nested_length(pred_res) == 1: - return self._zoopt_address_score_single(sol.get_x(), pred_res, pred_res_prob, key) + address_idx = np.where(sol.get_x() != 0)[0] + candidates = self.address_by_idx(pred_res, key, address_idx) + if len(candidates) > 0: + return np.min(self._get_cost_list(pred_res, pred_res_prob, candidates)) else: - all_address_flag = reform_idx(sol.get_x(), pred_res) - lefted_idx = [i for i in range(len(pred_res))] - candidate_size = [] - while lefted_idx: - temp_idx = [] - temp_idx.append(lefted_idx.pop(0)) - max_candidate_idx = [] - found = False - for idx in range(-1, len(pred_res)): - if (not idx in temp_idx) and (idx >= 0): - temp_idx.append(idx) - - pred = [] - k = [] - address_flag = [] - for idx in temp_idx: - pred.append(pred_res[idx]) - k.append(key[idx]) - address_flag += list(all_address_flag[idx]) - address_idx = np.where(np.array(address_flag) != 0)[0] - candidate = self.address_by_idx(pred, k, address_idx) - if len(candidate) == 0: - if len(temp_idx) > 1: - temp_idx.pop() - else: - if len(temp_idx) > len(max_candidate_idx): - found = True - max_candidate_idx = temp_idx.copy() - removed = [i for i in lefted_idx if i in max_candidate_idx] - - if found: - candidate_size.append(len(removed) + 1) - lefted_idx = [i for i in lefted_idx if i not in max_candidate_idx] - - candidate_size.sort() - score = 0 - import math - for i in range(0, len(candidate_size)): - score -= math.exp(-i) * candidate_size[i] - - # score = 0 - # for idx in range(nested_length(pred_res)): - # score += self._zoopt_address_score_single(all_address_flag[idx], [pred_res[idx]], [pred_res_prob[idx]], [key[idx]]) - return score + return len(pred_res) def _constrain_address_num(self, solution, max_address_num): x = solution.get_x() @@ -143,15 +105,63 @@ class AbducerBase(abc.ABC): candidate = self._get_one_candidate(pred_res, pred_res_prob, candidates) return candidate - def abduce_rules(self, pred_res): - return self.kb.abduce_rules(pred_res) - def batch_abduce(self, data, max_address=-1, require_more_address=0): Z1, Z2, Y = data return [self.abduce((z, prob, y), max_address, require_more_address) for z, prob, y in zip(Z1, Z2, Y)] - def __call__(self, Z, Y, max_address_num=-1, require_more_address=0): - return self.batch_abduce(Z, Y, max_address_num, require_more_address) + def __call__(self, Z, Y, max_address=-1, require_more_address=0): + return self.batch_abduce(Z, Y, max_address, require_more_address) + +class HED_Abducer(AbducerBase): + def __init__(self, kb, dist_func='hamming'): + super().__init__(kb, dist_func, zoopt=True) + + def _address_by_idxs(self, pred_res, key, all_address_flag, idxs): + pred = [] + k = [] + address_flag = [] + for idx in idxs: + pred.append(pred_res[idx]) + k.append(key[idx]) + address_flag += list(all_address_flag[idx]) + address_idx = np.where(np.array(address_flag) != 0)[0] + candidate = self.address_by_idx(pred, k, address_idx) + return candidate + + def _zoopt_address_score(self, pred_res, pred_res_prob, key, sol): + all_address_flag = reform_idx(sol.get_x(), pred_res) + lefted_idxs = [i for i in range(len(pred_res))] + candidate_size = [] + while lefted_idxs: + idxs = [] + idxs.append(lefted_idxs.pop(0)) + max_candidate_idxs = [] + found = False + for idx in range(-1, len(pred_res)): + if (not idx in idxs) and (idx >= 0): + idxs.append(idx) + candidate = self._address_by_idxs(pred_res, key, all_address_flag, idxs) + if len(candidate) == 0: + if len(idxs) > 1: + idxs.pop() + else: + if len(idxs) > len(max_candidate_idxs): + found = True + max_candidate_idxs = idxs.copy() + removed = [i for i in lefted_idxs if i in max_candidate_idxs] + if found: + candidate_size.append(len(removed) + 1) + lefted_idxs = [i for i in lefted_idxs if i not in max_candidate_idxs] + candidate_size.sort() + score = 0 + import math + for i in range(0, len(candidate_size)): + score -= math.exp(-i) * candidate_size[i] + return score + + def abduce_rules(self, pred_res): + return self.kb.abduce_rules(pred_res) + if __name__ == '__main__': from kb import add_KB, prolog_KB, HWF_KB, HED_prolog_KB @@ -293,7 +303,7 @@ if __name__ == '__main__': print() kb = HED_prolog_KB(pseudo_label_list=[1, 0, '+', '='], pl_file='../examples/datasets/hed/learn_add.pl') - abd = AbducerBase(kb, zoopt=True) + abd = HED_Abducer(kb) consist_exs = [[1, 1, '+', 0, '=', 1, 1], [1, '+', 1, '=', 1, 0], [0, '+', 0, '=', 0]] inconsist_exs = [[1, '+', 0, '=', 0], [1, '=', 1, '=', 0], [0, '=', 0, '=', 1, 1]] rules = ['my_op([0], [0], [0])', 'my_op([1], [1], [1, 0])'] @@ -312,4 +322,4 @@ if __name__ == '__main__': print() abduced_rules = abd.abduce_rules(consist_exs) - print(abduced_rules) + print(abduced_rules) \ No newline at end of file From 84d2443163705ccaa584df228d03b42e533e5dc4 Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Thu, 16 Mar 2023 09:01:19 +0800 Subject: [PATCH 204/601] add HED_Abducer --- abl/abducer/abducer_base.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index b7edd4c..d5bff1e 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -10,13 +10,10 @@ # # ================================================================# -import sys -sys.path.append('/home/huwc/ABL-Package/abl') - import abc import numpy as np from zoopt import Dimension, Objective, Parameter, Opt -from utils.utils import confidence_dist, flatten, reform_idx, hamming_dist +from ..utils.utils import confidence_dist, flatten, reform_idx, hamming_dist class AbducerBase(abc.ABC): def __init__(self, kb, dist_func='hamming', zoopt=False): From 7b4c1b6390a2cc946e1dc67e5bd759d03eacc458 Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Thu, 16 Mar 2023 09:03:36 +0800 Subject: [PATCH 205/601] Remove unnecessary functions --- abl/utils/utils.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/abl/utils/utils.py b/abl/utils/utils.py index a0d5cd1..05e6f1c 100644 --- a/abl/utils/utils.py +++ b/abl/utils/utils.py @@ -3,11 +3,6 @@ from .plog import INFO from collections import OrderedDict from itertools import chain -def nested_length(l): - if not isinstance(l[0], (list, tuple)): - return 1 - return len(l) - def flatten(l): if not isinstance(l[0], (list, tuple)): return l From 8511d618baf59563d3d55ade88c4d34a7795d367 Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Thu, 16 Mar 2023 09:12:35 +0800 Subject: [PATCH 206/601] Update abducer examples --- abl/abducer/abducer_base.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index d5bff1e..f24c60d 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -10,10 +10,13 @@ # # ================================================================# +import sys +sys.path.append('/home/huwc/ABL-Package/abl') + import abc import numpy as np from zoopt import Dimension, Objective, Parameter, Opt -from ..utils.utils import confidence_dist, flatten, reform_idx, hamming_dist +from utils.utils import confidence_dist, flatten, reform_idx, hamming_dist class AbducerBase(abc.ABC): def __init__(self, kb, dist_func='hamming', zoopt=False): @@ -302,21 +305,28 @@ if __name__ == '__main__': kb = HED_prolog_KB(pseudo_label_list=[1, 0, '+', '='], pl_file='../examples/datasets/hed/learn_add.pl') abd = HED_Abducer(kb) consist_exs = [[1, 1, '+', 0, '=', 1, 1], [1, '+', 1, '=', 1, 0], [0, '+', 0, '=', 0]] - inconsist_exs = [[1, '+', 0, '=', 0], [1, '=', 1, '=', 0], [0, '=', 0, '=', 1, 1]] + inconsist_exs1 = [[1, 1, '+', 0, '=', 1, 1], [1, '+', 1, '=', 1, 0], [0, '+', 0, '=', 0], [0, '+', 0, '=', 1]] + inconsist_exs2 = [[1, '+', 0, '=', 0], [1, '=', 1, '=', 0], [0, '=', 0, '=', 1, 1]] rules = ['my_op([0], [0], [0])', 'my_op([1], [1], [1, 0])'] + print('HED_kb logic forward') print(kb.logic_forward(consist_exs)) - print(kb.logic_forward(inconsist_exs)) + print(kb.logic_forward(inconsist_exs1), kb.logic_forward(inconsist_exs2)) print() + print('HED_kb consist rule') print(kb.consist_rule([1, '+', 1, '=', 1, 0], rules)) print(kb.consist_rule([1, '+', 1, '=', 1, 1], rules)) print() + print('HED_Abducer abduce') res = abd.abduce((consist_exs, [[[None]]] * len(consist_exs), [None] * len(consist_exs))) print(res) - res = abd.abduce((inconsist_exs, [[[None]]] * len(consist_exs), [None] * len(inconsist_exs))) + res = abd.abduce((inconsist_exs1, [[[None]]] * len(inconsist_exs1), [None] * len(inconsist_exs1))) + print(res) + res = abd.abduce((inconsist_exs2, [[[None]]] * len(inconsist_exs2), [None] * len(inconsist_exs2))) print(res) print() + print('HED_Abducer abduce rules') abduced_rules = abd.abduce_rules(consist_exs) print(abduced_rules) \ No newline at end of file From 2d605871673c27ae8e3c2470464cd88f8be08148 Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Thu, 16 Mar 2023 09:13:23 +0800 Subject: [PATCH 207/601] Update abducer examples --- abl/abducer/abducer_base.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index f24c60d..b0c0d8f 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -10,13 +10,10 @@ # # ================================================================# -import sys -sys.path.append('/home/huwc/ABL-Package/abl') - import abc import numpy as np from zoopt import Dimension, Objective, Parameter, Opt -from utils.utils import confidence_dist, flatten, reform_idx, hamming_dist +from ..utils.utils import confidence_dist, flatten, reform_idx, hamming_dist class AbducerBase(abc.ABC): def __init__(self, kb, dist_func='hamming', zoopt=False): From 5884584dfe77de85c1795601adb28a37c33c6f29 Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Thu, 16 Mar 2023 09:33:30 +0800 Subject: [PATCH 208/601] Update batch_abduce --- abl/abducer/abducer_base.py | 84 ++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 43 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index b0c0d8f..4597292 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -76,7 +76,6 @@ class AbducerBase(abc.ABC): return solution def address_by_idx(self, pred_res, key, address_idx): - # print(pred_res, address_idx) return self.kb.address_by_idx(pred_res, key, address_idx) def abduce(self, data, max_address=-1, require_more_address=0): @@ -102,9 +101,8 @@ class AbducerBase(abc.ABC): candidate = self._get_one_candidate(pred_res, pred_res_prob, candidates) return candidate - def batch_abduce(self, data, max_address=-1, require_more_address=0): - Z1, Z2, Y = data - return [self.abduce((z, prob, y), max_address, require_more_address) for z, prob, y in zip(Z1, Z2, Y)] + def batch_abduce(self, Z, Y, max_address=-1, require_more_address=0): + return [self.abduce((z, prob, y), max_address, require_more_address) for z, prob, y in zip(Z['cls'], Z['prob'], Y)] def __call__(self, Z, Y, max_address=-1, require_more_address=0): return self.batch_abduce(Z, Y, max_address, require_more_address) @@ -169,60 +167,60 @@ if __name__ == '__main__': print('add_KB with GKB:') kb = add_KB(GKB_flag=True) abd = AbducerBase(kb, 'confidence') - res = abd.batch_abduce(([[1, 1]], prob1, [8]), max_address=2, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob1}, [8], max_address=2, require_more_address=0) print(res) - res = abd.batch_abduce(([[1, 1]], prob2, [8]), max_address=2, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob2}, [8], max_address=2, require_more_address=0) print(res) - res = abd.batch_abduce(([[1, 1]], prob1, [17]), max_address=2, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob1}, [17], max_address=2, require_more_address=0) print(res) - res = abd.batch_abduce(([[1, 1]], prob1, [17]), max_address=1, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob1}, [17], max_address=1, require_more_address=0) print(res) - res = abd.batch_abduce(([[1, 1]], prob1, [20]), max_address=2, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob1}, [20], max_address=2, require_more_address=0) print(res) print() print('add_KB without GKB:') kb = add_KB() abd = AbducerBase(kb, 'confidence') - res = abd.batch_abduce(([[1, 1]], prob1, [8]), max_address=2, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob1}, [8], max_address=2, require_more_address=0) print(res) - res = abd.batch_abduce(([[1, 1]], prob2, [8]), max_address=2, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob2}, [8], max_address=2, require_more_address=0) print(res) - res = abd.batch_abduce(([[1, 1]], prob1, [17]), max_address=2, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob1}, [17], max_address=2, require_more_address=0) print(res) - res = abd.batch_abduce(([[1, 1]], prob1, [17]), max_address=1, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob1}, [17], max_address=1, require_more_address=0) print(res) - res = abd.batch_abduce(([[1, 1]], prob1, [20]), max_address=2, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob1}, [20], max_address=2, require_more_address=0) print(res) print() print('prolog_KB with add.pl:') kb = prolog_KB(pseudo_label_list=list(range(10)), pl_file='../examples/datasets/mnist_add/add.pl') abd = AbducerBase(kb, 'confidence') - res = abd.batch_abduce(([[1, 1]], prob1, [8]), max_address=2, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob1}, [8], max_address=2, require_more_address=0) print(res) - res = abd.batch_abduce(([[1, 1]], prob2, [8]), max_address=2, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob2}, [8], max_address=2, require_more_address=0) print(res) - res = abd.batch_abduce(([[1, 1]], prob1, [17]), max_address=2, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob1}, [17], max_address=2, require_more_address=0) print(res) - res = abd.batch_abduce(([[1, 1]], prob1, [17]), max_address=1, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob1}, [17], max_address=1, require_more_address=0) print(res) - res = abd.batch_abduce(([[1, 1]], prob1, [20]), max_address=2, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob1}, [20], max_address=2, require_more_address=0) print(res) print() print('prolog_KB with add.pl using zoopt:') kb = prolog_KB(pseudo_label_list=list(range(10)), pl_file='../examples/datasets/mnist_add/add.pl') abd = AbducerBase(kb, 'confidence', zoopt=True) - res = abd.batch_abduce(([[1, 1]], prob1, [8]), max_address=2, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob1}, [8], max_address=2, require_more_address=0) print(res) - res = abd.batch_abduce(([[1, 1]], prob2, [8]), max_address=2, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob2}, [8], max_address=2, require_more_address=0) print(res) - res = abd.batch_abduce(([[1, 1]], prob1, [17]), max_address=2, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob1}, [17], max_address=2, require_more_address=0) print(res) - res = abd.batch_abduce(([[1, 1]], prob1, [17]), max_address=1, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob1}, [17], max_address=1, require_more_address=0) print(res) - res = abd.batch_abduce(([[1, 1]], prob1, [20]), max_address=2, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1]], 'prob':prob1}, [20], max_address=2, require_more_address=0) print(res) print() @@ -232,70 +230,70 @@ if __name__ == '__main__': kb = add_KB() abd = AbducerBase(kb, 'confidence') - res = abd.batch_abduce(([[1, 1], [1, 2]], multiple_prob, [4, 8]), max_address=4, require_more_address=0) + res = abd.batch_abduce({'cls':[[1, 1], [1, 2]], 'prob':multiple_prob}, [4, 8], max_address=4, require_more_address=0) print(res) - res = abd.batch_abduce(([[1, 1], [1, 2]], multiple_prob, [4, 8]), max_address=4, require_more_address=1) + res = abd.batch_abduce({'cls':[[1, 1], [1, 2]], 'prob':multiple_prob}, [4, 8], max_address=4, require_more_address=1) print(res) print() print('HWF_KB with GKB, max_err=0.1') kb = HWF_KB(len_list=[1, 3, 5], GKB_flag=True, max_err = 0.1) abd = AbducerBase(kb, 'hamming') - res = abd.batch_abduce(([['5', '+', '2']], [None], [3]), max_address=2, require_more_address=0) + res = abd.batch_abduce({'cls':[['5', '+', '2']], 'prob':[None]}, [3], max_address=2, require_more_address=0) print(res) - res = abd.batch_abduce(([['5', '+', '9']], [None], [65]), max_address=3, require_more_address=0) + res = abd.batch_abduce({'cls':[['5', '+', '9']], 'prob':[None]}, [65], max_address=3, require_more_address=0) print(res) - res = abd.batch_abduce(([['5', '8', '8', '8', '8']], [None], [3.17]), max_address=5, require_more_address=3) + res = abd.batch_abduce({'cls':[['5', '8', '8', '8', '8']], 'prob':[None]}, [3.17], max_address=5, require_more_address=3) print(res) print() print('HWF_KB without GKB, max_err=0.1') kb = HWF_KB(len_list=[1, 3, 5], max_err = 0.1) abd = AbducerBase(kb, 'hamming') - res = abd.batch_abduce(([['5', '+', '2']], [None], [3]), max_address=2, require_more_address=0) + res = abd.batch_abduce({'cls':[['5', '+', '2']], 'prob':[None]}, [3], max_address=2, require_more_address=0) print(res) - res = abd.batch_abduce(([['5', '+', '9']], [None], [65]), max_address=3, require_more_address=0) + res = abd.batch_abduce({'cls':[['5', '+', '9']], 'prob':[None]}, [65], max_address=3, require_more_address=0) print(res) - res = abd.batch_abduce(([['5', '8', '8', '8', '8']], [None], [3.17]), max_address=5, require_more_address=3) + res = abd.batch_abduce({'cls':[['5', '8', '8', '8', '8']], 'prob':[None]}, [3.17], max_address=5, require_more_address=3) print(res) print() print('HWF_KB with GKB, max_err=1') kb = HWF_KB(len_list=[1, 3, 5], GKB_flag=True, max_err = 1) abd = AbducerBase(kb, 'hamming') - res = abd.batch_abduce(([['5', '+', '9']], [None], [65]), max_address=3, require_more_address=0) + res = abd.batch_abduce({'cls':[['5', '+', '9']], 'prob':[None]}, [65], max_address=3, require_more_address=0) print(res) - res = abd.batch_abduce(([['5', '+', '2']], [None], [1.67]), max_address=3, require_more_address=0) + res = abd.batch_abduce({'cls':[['5', '+', '2']], 'prob':[None]}, [1.67], max_address=3, require_more_address=0) print(res) - res = abd.batch_abduce(([['5', '8', '8', '8', '8']], [None], [3.17]), max_address=5, require_more_address=3) + res = abd.batch_abduce({'cls':[['5', '8', '8', '8', '8']], 'prob':[None]}, [3.17], max_address=5, require_more_address=3) print(res) print() print('HWF_KB without GKB, max_err=1') kb = HWF_KB(len_list=[1, 3, 5], max_err = 1) abd = AbducerBase(kb, 'hamming') - res = abd.batch_abduce(([['5', '+', '9']], [None], [65]), max_address=3, require_more_address=0) + res = abd.batch_abduce({'cls':[['5', '+', '9']], 'prob':[None]}, [65], max_address=3, require_more_address=0) print(res) - res = abd.batch_abduce(([['5', '+', '2']], [None], [1.67]), max_address=3, require_more_address=0) + res = abd.batch_abduce({'cls':[['5', '+', '2']], 'prob':[None]}, [1.67], max_address=3, require_more_address=0) print(res) - res = abd.batch_abduce(([['5', '8', '8', '8', '8']], [None], [3.17]), max_address=5, require_more_address=3) + res = abd.batch_abduce({'cls':[['5', '8', '8', '8', '8']], 'prob':[None]}, [3.17], max_address=5, require_more_address=3) print(res) print() print('HWF_KB with multiple inputs at once:') kb = HWF_KB(len_list=[1, 3, 5], max_err = 0.1) abd = AbducerBase(kb, 'hamming') - res = abd.batch_abduce(([['5', '+', '2'], ['5', '+', '9']], [None, None], [3, 64]), max_address=1, require_more_address=0) + res = abd.batch_abduce({'cls':[['5', '+', '2'], ['5', '+', '9']], 'prob':[None, None]}, [3, 64], max_address=1, require_more_address=0) print(res) - res = abd.batch_abduce(([['5', '+', '2'], ['5', '+', '9']], [None, None], [3, 64]), max_address=3, require_more_address=0) + res = abd.batch_abduce({'cls':[['5', '+', '2'], ['5', '+', '9']], 'prob':[None, None]}, [3, 64], max_address=3, require_more_address=0) print(res) - res = abd.batch_abduce(([['5', '+', '2'], ['5', '+', '9']], [None, None], [3, 65]), max_address=3, require_more_address=0) + res = abd.batch_abduce({'cls':[['5', '+', '2'], ['5', '+', '9']], 'prob':[None, None]}, [3, 65], max_address=3, require_more_address=0) print(res) print() print('max_address is float') - res = abd.batch_abduce(([['5', '+', '2'], ['5', '+', '9']], [None, None], [3, 64]), max_address=0.5, require_more_address=0) + res = abd.batch_abduce({'cls':[['5', '+', '2'], ['5', '+', '9']], 'prob':[None, None]}, [3, 64], max_address=0.5, require_more_address=0) print(res) - res = abd.batch_abduce(([['5', '+', '2'], ['5', '+', '9']], [None, None], [3, 64]), max_address=0.9, require_more_address=0) + res = abd.batch_abduce({'cls':[['5', '+', '2'], ['5', '+', '9']], 'prob':[None, None]}, [3, 64], max_address=0.9, require_more_address=0) print(res) print() From e0d4abbd3bbb09207f9e76a7f08e417148f7460a Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Thu, 16 Mar 2023 09:37:41 +0800 Subject: [PATCH 209/601] Save option for mnist_add --- examples/example.py | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/examples/example.py b/examples/example.py index c74f1b3..39e8c3f 100644 --- a/examples/example.py +++ b/examples/example.py @@ -32,31 +32,37 @@ from abl import framework_hed def run_test(): - # kb = add_KB(True) + kb = add_KB() # kb = HWF_KB(True) - # abducer = AbducerBase(kb) + abducer = AbducerBase(kb, 'confidence') - kb = prolog_KB(pseudo_label_list=[1, 0, '+', '='], pl_file='../examples/datasets/hed/learn_add.pl') - abducer = AbducerBase(kb, zoopt=True, multiple_predictions=True) + # kb = prolog_KB(pseudo_label_list=[1, 0, '+', '='], pl_file='../examples/datasets/hed/learn_add.pl') + # abducer = AbducerBase(kb, zoopt=True, multiple_predictions=True) recorder = logger() - total_train_data = get_hed(train=True) - train_data, val_data = split_equation(total_train_data, 3, 1) - test_data = get_hed(train=False) + # total_train_data = get_hed(train=True) + # train_data, val_data = split_equation(total_train_data, 3, 1) + # test_data = get_hed(train=False) - # cls = LeNet5(num_classes=len(kb.pseudo_label_list), image_size=(train_data[0][0][0].shape[1:])) - cls = SymbolNet(num_classes=len(kb.pseudo_label_list)) + train_data = get_mnist_add(train = True, get_pseudo_label = True) + test_data = get_mnist_add(train = False, get_pseudo_label = True) + + # train_data = get_hwf(train = True, get_pseudo_label = True) + # test_data = get_hwf(train = False, get_pseudo_label = True) + + cls = LeNet5(num_classes=len(kb.pseudo_label_list), image_size=(train_data[0][0][0].shape[1:])) + # cls = SymbolNet(num_classes=len(kb.pseudo_label_list)) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - framework_hed.hed_pretrain(kb, cls, recorder) + # framework_hed.hed_pretrain(kb, cls, recorder) criterion = nn.CrossEntropyLoss() - optimizer = torch.optim.RMSprop(cls.parameters(), lr=0.001, weight_decay=1e-6) - # optimizer = torch.optim.Adam(cls.parameters(), lr=0.00001, betas=(0.9, 0.99)) + # optimizer = torch.optim.RMSprop(cls.parameters(), lr=0.001, weight_decay=1e-6) + optimizer = torch.optim.Adam(cls.parameters(), lr=0.001, betas=(0.9, 0.99)) - base_model = BasicModel(cls, criterion, optimizer, device, save_interval=1, save_dir=recorder.save_dir, batch_size=32, num_epochs=10, recorder=recorder) + base_model = BasicModel(cls, criterion, optimizer, device, save_interval=1, save_dir=recorder.save_dir, batch_size=32, num_epochs=1, recorder=recorder) model = WABLBasicModel(base_model, kb.pseudo_label_list) # train_X, train_Z, train_Y = get_mnist_add(train = True, get_pseudo_label = True) @@ -65,8 +71,10 @@ def run_test(): # train_data = get_hwf(train = True, get_pseudo_label = True) # test_data = get_hwf(train = False, get_pseudo_label = True) - model, mapping = framework_hed.train_with_rule(model, abducer, train_data, val_data, select_num=10, min_len=5, max_len=8) - framework_hed.hed_test(model, abducer, mapping, train_data, test_data, min_len=5, max_len=8) + # model, mapping = framework_hed.train_with_rule(model, abducer, train_data, val_data, select_num=10, min_len=5, max_len=8) + # framework_hed.hed_test(model, abducer, mapping, train_data, test_data, min_len=5, max_len=8) + + framework_hed.train(model, abducer, train_data, test_data, sample_num=10000, verbose=1) recorder.dump() return True From 2d54e7023d45860f93041ff6f7f42028c4882c6f Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Thu, 16 Mar 2023 09:49:44 +0800 Subject: [PATCH 210/601] Update HED example --- abl/framework_hed.py | 6 ++---- examples/example.py | 42 +++++++++++++++++++++--------------------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/abl/framework_hed.py b/abl/framework_hed.py index ab88318..76c57fa 100644 --- a/abl/framework_hed.py +++ b/abl/framework_hed.py @@ -172,9 +172,6 @@ def abduce_and_train(model, abducer, mapping, train_X_true, select_num): if len(consistent_idx) == 0: return 0, 0, None - if len(mappings) > 1: - INFO('Final mapping is: ', mapping) - INFO('Train pool size is:', len(flatten(consistent_pred_res))) INFO("Start to use abduced pseudo label to train model...") model.train([X[idx] for idx in consistent_idx], remapping_res(consistent_pred_res, mapping)) @@ -214,7 +211,7 @@ def get_rules_from_data(model, abducer, mapping, train_X_true, samples_per_rule, consistent_idx = [] consistent_pred_res = [] for idx in range(len(pred_res)): - if abducer.kb.logic_forward(pred_res[idx]): + if abducer.kb.logic_forward([pred_res[idx]]): consistent_idx.append(idx) consistent_pred_res.append(pred_res[idx]) @@ -296,6 +293,7 @@ def train_with_rule(model, abducer, train_data, val_data, select_num=10, min_len break else: if equation_len == min_len: + INFO('Final mapping is: ', mapping) model.cls_list[0].model.load_state_dict(torch.load("./weights/pretrain_weights.pth")) else: model.cls_list[0].model.load_state_dict(torch.load("./weights/weights_%d.pth" % (equation_len - 1))) diff --git a/examples/example.py b/examples/example.py index 39e8c3f..0f75895 100644 --- a/examples/example.py +++ b/examples/example.py @@ -22,8 +22,8 @@ from abl.models.basic_model import BasicModel, BasicDataset from abl.models.wabl_models import DecisionTree, WABLBasicModel from multiprocessing import Pool -from abl.abducer.abducer_base import AbducerBase -from abl.abducer.kb import add_KB, HWF_KB, prolog_KB +from abl.abducer.abducer_base import AbducerBase, HED_Abducer +from abl.abducer.kb import add_KB, HWF_KB, prolog_KB, HED_prolog_KB from datasets.mnist_add.get_mnist_add import get_mnist_add from datasets.hwf.get_hwf import get_hwf from datasets.hed.get_hed import get_hed, split_equation @@ -32,37 +32,37 @@ from abl import framework_hed def run_test(): - kb = add_KB() - # kb = HWF_KB(True) - abducer = AbducerBase(kb, 'confidence') + # kb = add_KB() + # kb = HWF_KB() + # abducer = AbducerBase(kb, 'confidence') - # kb = prolog_KB(pseudo_label_list=[1, 0, '+', '='], pl_file='../examples/datasets/hed/learn_add.pl') - # abducer = AbducerBase(kb, zoopt=True, multiple_predictions=True) + kb = HED_prolog_KB(pseudo_label_list=[1, 0, '+', '='], pl_file='../examples/datasets/hed/learn_add.pl') + abducer = HED_Abducer(kb) recorder = logger() - # total_train_data = get_hed(train=True) - # train_data, val_data = split_equation(total_train_data, 3, 1) - # test_data = get_hed(train=False) + total_train_data = get_hed(train=True) + train_data, val_data = split_equation(total_train_data, 3, 1) + test_data = get_hed(train=False) - train_data = get_mnist_add(train = True, get_pseudo_label = True) - test_data = get_mnist_add(train = False, get_pseudo_label = True) + # train_data = get_mnist_add(train = True, get_pseudo_label = True) + # test_data = get_mnist_add(train = False, get_pseudo_label = True) # train_data = get_hwf(train = True, get_pseudo_label = True) # test_data = get_hwf(train = False, get_pseudo_label = True) - cls = LeNet5(num_classes=len(kb.pseudo_label_list), image_size=(train_data[0][0][0].shape[1:])) - # cls = SymbolNet(num_classes=len(kb.pseudo_label_list)) + # cls = LeNet5(num_classes=len(kb.pseudo_label_list), image_size=(train_data[0][0][0].shape[1:])) + cls = SymbolNet(num_classes=len(kb.pseudo_label_list)) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - # framework_hed.hed_pretrain(kb, cls, recorder) + framework_hed.hed_pretrain(kb, cls, recorder) criterion = nn.CrossEntropyLoss() - # optimizer = torch.optim.RMSprop(cls.parameters(), lr=0.001, weight_decay=1e-6) - optimizer = torch.optim.Adam(cls.parameters(), lr=0.001, betas=(0.9, 0.99)) + optimizer = torch.optim.RMSprop(cls.parameters(), lr=0.001, weight_decay=1e-6) + # optimizer = torch.optim.Adam(cls.parameters(), lr=0.001, betas=(0.9, 0.99)) - base_model = BasicModel(cls, criterion, optimizer, device, save_interval=1, save_dir=recorder.save_dir, batch_size=32, num_epochs=1, recorder=recorder) + base_model = BasicModel(cls, criterion, optimizer, device, save_interval=1, save_dir=recorder.save_dir, batch_size=32, num_epochs=10, recorder=recorder) model = WABLBasicModel(base_model, kb.pseudo_label_list) # train_X, train_Z, train_Y = get_mnist_add(train = True, get_pseudo_label = True) @@ -71,10 +71,10 @@ def run_test(): # train_data = get_hwf(train = True, get_pseudo_label = True) # test_data = get_hwf(train = False, get_pseudo_label = True) - # model, mapping = framework_hed.train_with_rule(model, abducer, train_data, val_data, select_num=10, min_len=5, max_len=8) - # framework_hed.hed_test(model, abducer, mapping, train_data, test_data, min_len=5, max_len=8) + model, mapping = framework_hed.train_with_rule(model, abducer, train_data, val_data, select_num=10, min_len=5, max_len=8) + framework_hed.hed_test(model, abducer, mapping, train_data, test_data, min_len=5, max_len=8) - framework_hed.train(model, abducer, train_data, test_data, sample_num=10000, verbose=1) + # framework_hed.train(model, abducer, train_data, test_data, sample_num=10000, verbose=1) recorder.dump() return True From af84354bdacc0ab93c9d1d150420c76a679051bc Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Fri, 17 Mar 2023 11:33:54 +0800 Subject: [PATCH 211/601] Parallelizing batch_abduce --- abl/abducer/abducer_base.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index 4597292..96161a4 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -12,6 +12,7 @@ import abc import numpy as np +import multiprocessing from zoopt import Dimension, Objective, Parameter, Opt from ..utils.utils import confidence_dist, flatten, reform_idx, hamming_dist @@ -101,9 +102,20 @@ class AbducerBase(abc.ABC): candidate = self._get_one_candidate(pred_res, pred_res_prob, candidates) return candidate - def batch_abduce(self, Z, Y, max_address=-1, require_more_address=0): - return [self.abduce((z, prob, y), max_address, require_more_address) for z, prob, y in zip(Z['cls'], Z['prob'], Y)] + # def batch_abduce(self, Z, Y, max_address=-1, require_more_address=0): + # return [self.abduce((z, prob, y), max_address, require_more_address) for z, prob, y in zip(Z['cls'], Z['prob'], Y)] + + def _batch_abduce_helper(self, args): + z, prob, y, max_address, require_more_address = args + return self.abduce((z, prob, y), max_address, require_more_address) + def batch_abduce(self, Z, Y, max_address=-1, require_more_address=0): + pool = multiprocessing.Pool(processes=len(Z)) + results = pool.map(self._batch_abduce_helper, [(z, prob, y, max_address, require_more_address) for z, prob, y in zip(Z['cls'], Z['prob'], Y)]) + pool.close() + pool.join() + return results + def __call__(self, Z, Y, max_address=-1, require_more_address=0): return self.batch_abduce(Z, Y, max_address, require_more_address) From 953a88d15a90adca9d970c08f04ccf9b92d198f9 Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Fri, 17 Mar 2023 14:25:35 +0800 Subject: [PATCH 212/601] Examples for HWF --- examples/datasets/hwf/get_hwf.py | 8 +++---- examples/example.py | 41 +++++++++++++------------------- 2 files changed, 21 insertions(+), 28 deletions(-) diff --git a/examples/datasets/hwf/get_hwf.py b/examples/datasets/hwf/get_hwf.py index b478a15..87da5cf 100644 --- a/examples/datasets/hwf/get_hwf.py +++ b/examples/datasets/hwf/get_hwf.py @@ -7,7 +7,7 @@ img_transform = transforms.Compose([ transforms.Normalize((0.5,), (1,)) ]) -def get_data(file, get_pseudo_label, precision_num = 2): +def get_data(file, get_pseudo_label): X = [] if get_pseudo_label: Z = [] @@ -27,20 +27,20 @@ def get_data(file, get_pseudo_label, precision_num = 2): X.append(imgs) if get_pseudo_label: Z.append(imgs_pseudo_label) - Y.append(round(data[idx]['res'], precision_num)) + Y.append(data[idx]['res']) if get_pseudo_label: return X, Z, Y else: return X, None, Y -def get_hwf(train = True, get_pseudo_label = False, precision_num = 2): +def get_hwf(train = True, get_pseudo_label = False): if(train): file = './datasets/hwf/data/expr_train.json' else: file = './datasets/hwf/data/expr_test.json' - return get_data(file, get_pseudo_label, precision_num) + return get_data(file, get_pseudo_label) if __name__ == "__main__": train_X, train_Y = get_hwf(train = True) diff --git a/examples/example.py b/examples/example.py index 0f75895..df101e2 100644 --- a/examples/example.py +++ b/examples/example.py @@ -33,48 +33,41 @@ from abl import framework_hed def run_test(): # kb = add_KB() - # kb = HWF_KB() - # abducer = AbducerBase(kb, 'confidence') + kb = HWF_KB(GKB_flag=True) + abducer = AbducerBase(kb, 'confidence') - kb = HED_prolog_KB(pseudo_label_list=[1, 0, '+', '='], pl_file='../examples/datasets/hed/learn_add.pl') - abducer = HED_Abducer(kb) + # kb = HED_prolog_KB(pseudo_label_list=[1, 0, '+', '='], pl_file='../examples/datasets/hed/learn_add.pl') + # abducer = HED_Abducer(kb) recorder = logger() - total_train_data = get_hed(train=True) - train_data, val_data = split_equation(total_train_data, 3, 1) - test_data = get_hed(train=False) + # total_train_data = get_hed(train=True) + # train_data, val_data = split_equation(total_train_data, 3, 1) + # test_data = get_hed(train=False) - # train_data = get_mnist_add(train = True, get_pseudo_label = True) - # test_data = get_mnist_add(train = False, get_pseudo_label = True) + # train_data = get_mnist_add(train=True, get_pseudo_label=True) + # test_data = get_mnist_add(train=False, get_pseudo_label=True) - # train_data = get_hwf(train = True, get_pseudo_label = True) - # test_data = get_hwf(train = False, get_pseudo_label = True) + train_data = get_hwf(train=True, get_pseudo_label=True) + test_data = get_hwf(train=False, get_pseudo_label=True) # cls = LeNet5(num_classes=len(kb.pseudo_label_list), image_size=(train_data[0][0][0].shape[1:])) - cls = SymbolNet(num_classes=len(kb.pseudo_label_list)) + cls = SymbolNet(num_classes=len(kb.pseudo_label_list), image_size=(train_data[0][0][0].shape[1:])) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - framework_hed.hed_pretrain(kb, cls, recorder) + # framework_hed.hed_pretrain(kb, cls, recorder) criterion = nn.CrossEntropyLoss() optimizer = torch.optim.RMSprop(cls.parameters(), lr=0.001, weight_decay=1e-6) # optimizer = torch.optim.Adam(cls.parameters(), lr=0.001, betas=(0.9, 0.99)) - - base_model = BasicModel(cls, criterion, optimizer, device, save_interval=1, save_dir=recorder.save_dir, batch_size=32, num_epochs=10, recorder=recorder) + base_model = BasicModel(cls, criterion, optimizer, device, save_interval=1, save_dir=recorder.save_dir, batch_size=32, num_epochs=1, recorder=recorder) model = WABLBasicModel(base_model, kb.pseudo_label_list) - - # train_X, train_Z, train_Y = get_mnist_add(train = True, get_pseudo_label = True) - # test_X, test_Z, test_Y = get_mnist_add(train = False, get_pseudo_label = True) - - # train_data = get_hwf(train = True, get_pseudo_label = True) - # test_data = get_hwf(train = False, get_pseudo_label = True) - model, mapping = framework_hed.train_with_rule(model, abducer, train_data, val_data, select_num=10, min_len=5, max_len=8) - framework_hed.hed_test(model, abducer, mapping, train_data, test_data, min_len=5, max_len=8) + # model, mapping = framework_hed.train_with_rule(model, abducer, train_data, val_data, select_num=10, min_len=5, max_len=8) + # framework_hed.hed_test(model, abducer, mapping, train_data, test_data, min_len=5, max_len=8) - # framework_hed.train(model, abducer, train_data, test_data, sample_num=10000, verbose=1) + framework_hed.train(model, abducer, train_data, test_data, sample_num=-1, verbose=1) recorder.dump() return True From ee25a2c74e40d87a7afca5faa9579885fed3966e Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Fri, 17 Mar 2023 14:35:58 +0800 Subject: [PATCH 213/601] Modify filter_data --- abl/framework_hed.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/abl/framework_hed.py b/abl/framework_hed.py index 76c57fa..c8d1e2a 100644 --- a/abl/framework_hed.py +++ b/abl/framework_hed.py @@ -52,9 +52,9 @@ def result_statistics(pred_Z, Z, Y, logic_forward, char_acc_flag): def filter_data(X, abduced_Z): finetune_Z = [] finetune_X = [] - for abduced_x, abduced_z in zip(X, abduced_Z): - if abduced_z is not []: - finetune_X.append(abduced_x) + for x, abduced_z in zip(X, abduced_Z): + if len(abduced_z) > 0: + finetune_X.append(x) finetune_Z.append(abduced_z) return finetune_X, finetune_Z @@ -84,7 +84,6 @@ def train(model, abducer, train_data, test_data, epochs=50, sample_num=-1, verbo for epoch_idx in range(epochs): X, Z, Y = block_sample(train_X, train_Z, train_Y, sample_num, epoch_idx) preds_res = predict_func(X) - # input() abduced_Z = abduce_func(preds_res, Y) if ((epoch_idx + 1) % verbose == 0) or (epoch_idx == epochs - 1): From 33b5e25d3ff59c348300b9559f022d0463e44acb Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Mon, 20 Mar 2023 20:35:18 +0800 Subject: [PATCH 214/601] add test code for BasicModel --- tests/test_models.py | 75 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 tests/test_models.py diff --git a/tests/test_models.py b/tests/test_models.py new file mode 100644 index 0000000..b01b8c3 --- /dev/null +++ b/tests/test_models.py @@ -0,0 +1,75 @@ +import sys + +sys.path.insert(0, sys.path[0] + "/../") + +import os +import pytest +import torch +import torch.nn as nn +import numpy as np + +from abl.models.nn import LeNet5, SymbolNet +from abl.models.basic_model import BasicModel + + +class TestBasicModel(object): + @pytest.mark.parametrize("num_classes", [4, 10]) + @pytest.mark.parametrize("image_size", [(28, 28, 1), (45, 45, 1)]) + @pytest.mark.parametrize("cls", [LeNet5, SymbolNet]) + @pytest.mark.parametrize("criterion", [nn.CrossEntropyLoss]) + @pytest.mark.parametrize("optimizer", [torch.optim.RMSprop]) + @pytest.mark.parametrize("device", [torch.device("cpu"), torch.device("cuda:0")]) + def test_models(self, num_classes, image_size, cls, criterion, optimizer, device): + cls = cls(num_classes=num_classes, image_size=image_size) + criterion = criterion() + optimizer = optimizer(cls.parameters(), lr=0.001) + + self.num_classes = num_classes + self.image_size = image_size + self.model = BasicModel(cls, criterion, optimizer, device) + + self.data_X = [ + np.random.rand(image_size[2], image_size[0], image_size[1]).astype( + np.float32 + ) + for i in range(5) + ] + self.data_y = np.random.randint(0, num_classes, (5,)) + + self._test_fit() + self._test_predict() + self._test_predict_proba() + self._test_val() + self._test_save() + self._test_load() + + def _test_fit(self): + self.model.fit(X=self.data_X, y=self.data_y) + + def _test_predict(self): + predict_result = self.model.predict(X=self.data_X) + assert predict_result.dtype == int + assert predict_result.shape == (5,) + assert (0 <= predict_result).all() and (predict_result < self.num_classes).all() + + def _test_predict_proba(self): + predict_result = self.model.predict_proba(X=self.data_X) + assert predict_result.dtype == np.float32 + assert predict_result.shape == (5, self.num_classes) + assert (0 <= predict_result).all() and (predict_result <= 1).all() + + def _test_val(self): + accuracy = self.model.val(X=self.data_X, y=self.data_y) + assert type(accuracy) == float + assert 0 <= accuracy <= 1 + + def _test_save(self): + self.model.save(1, "results/test_models") + assert os.path.exists("results/test_models/1_net.pth") + assert os.path.exists("results/test_models/1_opt.pth") + os.remove("results/test_models/1_net.pth") + os.remove("results/test_models/1_opt.pth") + + def _test_load(self): + self.model.save(1, "results/test_models") + self.model.load(1, "results/test_models") From 1ac226676b5d89b21adecb2fe53794356c6ead38 Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Mon, 20 Mar 2023 22:07:15 +0800 Subject: [PATCH 215/601] add build-and-test workflow and related files --- .coveragerc | 8 ++++++ .github/workflows/build-and-test.yaml | 35 +++++++++++++++++++++++++++ requirements.txt | 6 +++++ 3 files changed, 49 insertions(+) create mode 100644 .coveragerc create mode 100644 .github/workflows/build-and-test.yaml create mode 100644 requirements.txt diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..5f18aae --- /dev/null +++ b/.coveragerc @@ -0,0 +1,8 @@ +[report] +show_missing = True + +[run] +disable_warnings = include-ignored +include = */abl/* +omit = + */abl/__init__.py \ No newline at end of file diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml new file mode 100644 index 0000000..45b2bd2 --- /dev/null +++ b/.github/workflows/build-and-test.yaml @@ -0,0 +1,35 @@ +name: ABL-Package-CI + +on: + push: + branches: [ main, Dev ] + pull_request: + branches: [ main ] + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + python-version: [3.8, 3.9] + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Display python version + run: python -c "import sys; print(sys.version)" + - name: Install package dependencies + run: | + python -m pip install --upgrade pip + pip install -r ./requirements.txt + - name: Run tests + run: | + pytest --cov-config=.coveragerc --cov-report=xml --cov=abl ./tests + - name: Publish code coverage + uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: ./coverage.xml \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..1c7dab4 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +numpy +pyswip==0.2.9 +pytest-cov +torch +torchvision +torchaudio \ No newline at end of file From b854ffd282d06da0ed77ad6577db13d4c4acbaef Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Mon, 20 Mar 2023 22:26:41 +0800 Subject: [PATCH 216/601] fix bug in BasicModel test --- .github/workflows/build-and-test.yaml | 6 +++++- abl/models/basic_model.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml index 45b2bd2..0e38b25 100644 --- a/.github/workflows/build-and-test.yaml +++ b/.github/workflows/build-and-test.yaml @@ -11,7 +11,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, windows-latest] + os: ubuntu-latest python-version: [3.8, 3.9] steps: - uses: actions/checkout@v2 @@ -25,6 +25,10 @@ jobs: run: | python -m pip install --upgrade pip pip install -r ./requirements.txt + - uses: Jimver/cuda-toolkit@v0.2.10 + id: cuda-toolkit + with: + cuda: '12.1.0' - name: Run tests run: | pytest --cov-config=.coveragerc --cov-report=xml --cov=abl ./tests diff --git a/abl/models/basic_model.py b/abl/models/basic_model.py index 8c137e2..9050365 100644 --- a/abl/models/basic_model.py +++ b/abl/models/basic_model.py @@ -251,7 +251,7 @@ class BasicModel: def save(self, epoch_id, save_dir): recorder = self.recorder if not os.path.exists(save_dir): - os.mkdir(save_dir) + os.makedirs(save_dir) recorder.print("Saving model and opter") save_path = os.path.join(save_dir, str(epoch_id) + "_net.pth") torch.save(self.model.state_dict(), save_path) From c844d8ffe549b35bd92abfe458801bfc7374ae91 Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Mon, 20 Mar 2023 22:31:16 +0800 Subject: [PATCH 217/601] fix bug in BasicModel test --- .github/workflows/build-and-test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml index 0e38b25..2c14f61 100644 --- a/.github/workflows/build-and-test.yaml +++ b/.github/workflows/build-and-test.yaml @@ -11,7 +11,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: ubuntu-latest + os: [ubuntu-latest] python-version: [3.8, 3.9] steps: - uses: actions/checkout@v2 From 4af9a0bf6b12511248374cd157ee4254b38eb7b0 Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Tue, 21 Mar 2023 09:13:43 +0800 Subject: [PATCH 218/601] add zoopt in requirements --- requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1c7dab4..78a9c6f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,5 @@ pyswip==0.2.9 pytest-cov torch torchvision -torchaudio \ No newline at end of file +torchaudio +zoopt \ No newline at end of file From 9db37dececbd906113557101cd9cf027c6339f3d Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Tue, 21 Mar 2023 10:02:13 +0800 Subject: [PATCH 219/601] remove cuda related test --- .github/workflows/build-and-test.yaml | 4 ---- tests/test_models.py | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml index 2c14f61..31dc9ec 100644 --- a/.github/workflows/build-and-test.yaml +++ b/.github/workflows/build-and-test.yaml @@ -25,10 +25,6 @@ jobs: run: | python -m pip install --upgrade pip pip install -r ./requirements.txt - - uses: Jimver/cuda-toolkit@v0.2.10 - id: cuda-toolkit - with: - cuda: '12.1.0' - name: Run tests run: | pytest --cov-config=.coveragerc --cov-report=xml --cov=abl ./tests diff --git a/tests/test_models.py b/tests/test_models.py index b01b8c3..8ea4383 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -18,7 +18,7 @@ class TestBasicModel(object): @pytest.mark.parametrize("cls", [LeNet5, SymbolNet]) @pytest.mark.parametrize("criterion", [nn.CrossEntropyLoss]) @pytest.mark.parametrize("optimizer", [torch.optim.RMSprop]) - @pytest.mark.parametrize("device", [torch.device("cpu"), torch.device("cuda:0")]) + @pytest.mark.parametrize("device", [torch.device("cpu")]) def test_models(self, num_classes, image_size, cls, criterion, optimizer, device): cls = cls(num_classes=num_classes, image_size=image_size) criterion = criterion() From 3a965b80138df25728e5519d97f5903aefb3f125 Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Tue, 21 Mar 2023 10:11:50 +0800 Subject: [PATCH 220/601] Modify pool --- abl/abducer/abducer_base.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/abl/abducer/abducer_base.py b/abl/abducer/abducer_base.py index 96161a4..441223f 100644 --- a/abl/abducer/abducer_base.py +++ b/abl/abducer/abducer_base.py @@ -10,9 +10,10 @@ # # ================================================================# +import os import abc import numpy as np -import multiprocessing +from multiprocessing import Pool from zoopt import Dimension, Objective, Parameter, Opt from ..utils.utils import confidence_dist, flatten, reform_idx, hamming_dist @@ -110,10 +111,8 @@ class AbducerBase(abc.ABC): return self.abduce((z, prob, y), max_address, require_more_address) def batch_abduce(self, Z, Y, max_address=-1, require_more_address=0): - pool = multiprocessing.Pool(processes=len(Z)) - results = pool.map(self._batch_abduce_helper, [(z, prob, y, max_address, require_more_address) for z, prob, y in zip(Z['cls'], Z['prob'], Y)]) - pool.close() - pool.join() + with Pool(processes=os.cpu_count()) as pool: + results = pool.map(self._batch_abduce_helper, [(z, prob, y, max_address, require_more_address) for z, prob, y in zip(Z['cls'], Z['prob'], Y)]) return results def __call__(self, Z, Y, max_address=-1, require_more_address=0): From df4d48c04accef6b5191e7ddb1e18c8a03f4a5ae Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Tue, 21 Mar 2023 10:26:22 +0800 Subject: [PATCH 221/601] add CI token to readme.md --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 512a68f..4181afb 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,6 @@ [![flake8 Lint](https://github.com/AbductiveLearning/ABL-Package/actions/workflows/lint.yml/badge.svg?branch=Dev)](https://github.com/AbductiveLearning/ABL-Package/actions/workflows/lint.yml) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) +[![ABL-Package-CI](https://github.com/AbductiveLearning/ABL-Package/actions/workflows/build-and-test.yaml/badge.svg?branch=Dev)](https://github.com/AbductiveLearning/ABL-Package/actions/workflows/build-and-test.yaml) # ABL Package From c5aeb045aa1f93ba30b67c02cf6f4f292233088f Mon Sep 17 00:00:00 2001 From: troyyyyy Date: Tue, 21 Mar 2023 12:57:03 +0800 Subject: [PATCH 222/601] add docs --- docs/ABL/Abductive Learning.rst | 5 + docs/ABL/Quick Start.rst | 52 + docs/Examples/MNISTadd.rst | 3 + docs/Makefile | 20 + docs/README.rst | 27 + .../doctrees/ABL/Abductive Learning.doctree | Bin 0 -> 2528 bytes docs/build/doctrees/ABL/Quick Start.doctree | Bin 0 -> 8680 bytes docs/build/doctrees/Examples/MNISTadd.doctree | Bin 0 -> 2352 bytes docs/build/doctrees/README.doctree | Bin 0 -> 4615 bytes docs/build/doctrees/environment.pickle | Bin 0 -> 41177 bytes docs/build/doctrees/index.doctree | Bin 0 -> 5341 bytes docs/build/html/.buildinfo | 4 + docs/build/html/ABL/Abductive Learning.html | 118 + docs/build/html/ABL/Quick Start.html | 171 ++ docs/build/html/Examples/MNISTadd.html | 115 + docs/build/html/README.html | 129 + .../_sources/ABL/Abductive Learning.rst.txt | 5 + .../html/_sources/ABL/Quick Start.rst.txt | 52 + .../html/_sources/Examples/MNISTadd.rst.txt | 3 + docs/build/html/_sources/README.rst.txt | 27 + docs/build/html/_sources/index.rst.txt | 15 + .../_sphinx_javascript_frameworks_compat.js | 123 + docs/build/html/_static/basic.css | 903 ++++++ docs/build/html/_static/css/badge_only.css | 1 + .../_static/css/fonts/Roboto-Slab-Bold.woff | Bin 0 -> 87624 bytes .../_static/css/fonts/Roboto-Slab-Bold.woff2 | Bin 0 -> 67312 bytes .../css/fonts/Roboto-Slab-Regular.woff | Bin 0 -> 86288 bytes .../css/fonts/Roboto-Slab-Regular.woff2 | Bin 0 -> 66444 bytes .../_static/css/fonts/fontawesome-webfont.eot | Bin 0 -> 165742 bytes .../_static/css/fonts/fontawesome-webfont.svg | 2671 +++++++++++++++++ .../_static/css/fonts/fontawesome-webfont.ttf | Bin 0 -> 165548 bytes .../css/fonts/fontawesome-webfont.woff | Bin 0 -> 98024 bytes .../css/fonts/fontawesome-webfont.woff2 | Bin 0 -> 77160 bytes .../_static/css/fonts/lato-bold-italic.woff | Bin 0 -> 323344 bytes .../_static/css/fonts/lato-bold-italic.woff2 | Bin 0 -> 193308 bytes .../html/_static/css/fonts/lato-bold.woff | Bin 0 -> 309728 bytes .../html/_static/css/fonts/lato-bold.woff2 | Bin 0 -> 184912 bytes .../_static/css/fonts/lato-normal-italic.woff | Bin 0 -> 328412 bytes .../css/fonts/lato-normal-italic.woff2 | Bin 0 -> 195704 bytes .../html/_static/css/fonts/lato-normal.woff | Bin 0 -> 309192 bytes .../html/_static/css/fonts/lato-normal.woff2 | Bin 0 -> 182708 bytes docs/build/html/_static/css/theme.css | 4 + docs/build/html/_static/doctools.js | 156 + .../html/_static/documentation_options.js | 14 + docs/build/html/_static/jquery.js | 2 + docs/build/html/_static/js/badge_only.js | 1 + .../_static/js/html5shiv-printshiv.min.js | 4 + docs/build/html/_static/js/html5shiv.min.js | 4 + docs/build/html/_static/js/theme.js | 1 + docs/build/html/_static/language_data.js | 199 ++ docs/build/html/_static/pygments.css | 74 + docs/build/html/_static/searchtools.js | 566 ++++ docs/build/html/_static/sphinx_highlight.js | 144 + docs/build/html/genindex.html | 113 + docs/build/html/index.html | 150 + docs/build/html/objects.inv | 5 + docs/build/html/search.html | 128 + docs/build/html/searchindex.js | 1 + docs/conf.py | 94 + docs/index.rst | 15 + docs/make.bat | 38 + docs/requirements.txt | 1 + 62 files changed, 6158 insertions(+) create mode 100644 docs/ABL/Abductive Learning.rst create mode 100644 docs/ABL/Quick Start.rst create mode 100644 docs/Examples/MNISTadd.rst create mode 100644 docs/Makefile create mode 100644 docs/README.rst create mode 100644 docs/build/doctrees/ABL/Abductive Learning.doctree create mode 100644 docs/build/doctrees/ABL/Quick Start.doctree create mode 100644 docs/build/doctrees/Examples/MNISTadd.doctree create mode 100644 docs/build/doctrees/README.doctree create mode 100644 docs/build/doctrees/environment.pickle create mode 100644 docs/build/doctrees/index.doctree create mode 100644 docs/build/html/.buildinfo create mode 100644 docs/build/html/ABL/Abductive Learning.html create mode 100644 docs/build/html/ABL/Quick Start.html create mode 100644 docs/build/html/Examples/MNISTadd.html create mode 100644 docs/build/html/README.html create mode 100644 docs/build/html/_sources/ABL/Abductive Learning.rst.txt create mode 100644 docs/build/html/_sources/ABL/Quick Start.rst.txt create mode 100644 docs/build/html/_sources/Examples/MNISTadd.rst.txt create mode 100644 docs/build/html/_sources/README.rst.txt create mode 100644 docs/build/html/_sources/index.rst.txt create mode 100644 docs/build/html/_static/_sphinx_javascript_frameworks_compat.js create mode 100644 docs/build/html/_static/basic.css create mode 100644 docs/build/html/_static/css/badge_only.css create mode 100644 docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff create mode 100644 docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 create mode 100644 docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff create mode 100644 docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 create mode 100644 docs/build/html/_static/css/fonts/fontawesome-webfont.eot create mode 100644 docs/build/html/_static/css/fonts/fontawesome-webfont.svg create mode 100644 docs/build/html/_static/css/fonts/fontawesome-webfont.ttf create mode 100644 docs/build/html/_static/css/fonts/fontawesome-webfont.woff create mode 100644 docs/build/html/_static/css/fonts/fontawesome-webfont.woff2 create mode 100644 docs/build/html/_static/css/fonts/lato-bold-italic.woff create mode 100644 docs/build/html/_static/css/fonts/lato-bold-italic.woff2 create mode 100644 docs/build/html/_static/css/fonts/lato-bold.woff create mode 100644 docs/build/html/_static/css/fonts/lato-bold.woff2 create mode 100644 docs/build/html/_static/css/fonts/lato-normal-italic.woff create mode 100644 docs/build/html/_static/css/fonts/lato-normal-italic.woff2 create mode 100644 docs/build/html/_static/css/fonts/lato-normal.woff create mode 100644 docs/build/html/_static/css/fonts/lato-normal.woff2 create mode 100644 docs/build/html/_static/css/theme.css create mode 100644 docs/build/html/_static/doctools.js create mode 100644 docs/build/html/_static/documentation_options.js create mode 100644 docs/build/html/_static/jquery.js create mode 100644 docs/build/html/_static/js/badge_only.js create mode 100644 docs/build/html/_static/js/html5shiv-printshiv.min.js create mode 100644 docs/build/html/_static/js/html5shiv.min.js create mode 100644 docs/build/html/_static/js/theme.js create mode 100644 docs/build/html/_static/language_data.js create mode 100644 docs/build/html/_static/pygments.css create mode 100644 docs/build/html/_static/searchtools.js create mode 100644 docs/build/html/_static/sphinx_highlight.js create mode 100644 docs/build/html/genindex.html create mode 100644 docs/build/html/index.html create mode 100644 docs/build/html/objects.inv create mode 100644 docs/build/html/search.html create mode 100644 docs/build/html/searchindex.js create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/make.bat create mode 100644 docs/requirements.txt diff --git a/docs/ABL/Abductive Learning.rst b/docs/ABL/Abductive Learning.rst new file mode 100644 index 0000000..47537b3 --- /dev/null +++ b/docs/ABL/Abductive Learning.rst @@ -0,0 +1,5 @@ +----------------------------- +Abductive Learning +----------------------------- + +What is ABL \ No newline at end of file diff --git a/docs/ABL/Quick Start.rst b/docs/ABL/Quick Start.rst new file mode 100644 index 0000000..4c7da0a --- /dev/null +++ b/docs/ABL/Quick Start.rst @@ -0,0 +1,52 @@ +--------------- +Quick Start +--------------- + +How to use + +.. contents:: Table of Contents + +Required packages +----------------- + +This package requires the following packages: + +- Python version above 3.x +- ``numpy`` http://www.numpy.org + +The easiest way to get these is to use +`pip `__ or +`conda `__ environment +manager. Typing the following command in your terminal will install all +required packages in your Python environment. + +.. code:: console + + $ conda install numpy + +or + +.. code:: console + + $ pip install numpy + +Getting and installing ABL +---------------------------- + +The easiest way to install ABL is to type ``pip install ABL`` in you +terminal/command line. + +If you want to install ABL by source code, download this project and +sequentially run following commands in your terminal/command line. + +.. code:: console + + $ python setup.py build + $ python setup.py install + +A quick example +--------------- + +Show an example. + +More examples are available in the **Example** part. diff --git a/docs/Examples/MNISTadd.rst b/docs/Examples/MNISTadd.rst new file mode 100644 index 0000000..c958334 --- /dev/null +++ b/docs/Examples/MNISTadd.rst @@ -0,0 +1,3 @@ +------------------------------------- +MNISTadd +------------------------------------- diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..9a4183c --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = ABL +SOURCEDIR = . +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/README.rst b/docs/README.rst new file mode 100644 index 0000000..18600c4 --- /dev/null +++ b/docs/README.rst @@ -0,0 +1,27 @@ +ABL +^^^^^^ + +ABL(Abductive Learning) is ... + +Installation +------------- + +ABL is distributed on PyPI and can be installed with ``pip``: + +.. code:: console + + $ pip install ABL + +Alternatively, to install ABL by source code, download this project and sequentially run following commands in your terminal/command line. + +.. code:: console + + $ python setup.py build + $ python setup.py install + + +Releases +-------- +`release 0.1`_ + +.. _release 0.1: https://github.com/AbductiveLearning/ABL-Package/releases/tag/v0.1 \ No newline at end of file diff --git a/docs/build/doctrees/ABL/Abductive Learning.doctree b/docs/build/doctrees/ABL/Abductive Learning.doctree new file mode 100644 index 0000000000000000000000000000000000000000..a94a3138765f1ad1f446acb975d6fe2b037f41b9 GIT binary patch literal 2528 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 M&0`Ja^`z7K52|cmApigX literal 0 HcmV?d00001 diff --git a/docs/build/doctrees/Examples/MNISTadd.doctree b/docs/build/doctrees/Examples/MNISTadd.doctree new file mode 100644 index 0000000000000000000000000000000000000000..b73f9c50f3c7c81a158d5699e2cd0a72c1462fd4 GIT binary patch literal 2352 zcmZ8jTW=gS6mFaDE!k|6mLjA!pbC{z(d-C)te@W&HWv&v%aVPw&4cqg(Y)JaCnedNrktX~VcnamY*&O0IqS zke>aU-li|($kGdEf-QK8w;)jnshH(Dy-snG#l2K++UgG+FT6CmQx`qa7lYSHjAGAA zulS9dIDC2b%O9`cJ+&ftU-4CTedFd`YQpGO6i$5-M{z{DD8)|fx51soyGm-F&cd9= zUFyA+^Wc$GPGUzgmjfOYiaG}n-#tys=4;48b$yuA;@t8@mI-m-=`vp>aUdRwv3MkQ z#Buy)CQQj^B3u-+AAbDxN>ixMtiPViv2&S3aHeY65`-2j+R_=OTDoP2S!n7kF;^vYupgnKF4vl zJqD|A+V`d)xxo1r?s|yJUZ!|&VT{+t^Bb3^x8r`MlMW?WEsQM_kcmTID^i#;v(&-l z!v^7s*9f_gUXXR0;jvX{`+gS3mRH7lqWBxG(&?SJE2!#@y?De|61DQw2e%gL#UA7H zu!OtG1+^Nrf`sL?1TylL7Ca}F-p7g5Rq%xC!Z1jsI0}Ao^4*D(_sYTqV(u6B@iB*HFA8!Ki%} z%8GQXLse@)f^b$-l?@)$2uiD6?)^1XIUblHt1|QHkgqD^IJv1=Q>5_ZjdZf%=K*2T z(YeZrv{4S$(;%M5F_LlMKdm7HHLogVLNt5@bf5- z6lkNDV4;$w^y%f{(>SSkMNkxuK`iQmjWaT*h&@k6{6u(Px$kE)z;0SydSUd`*ySw6 z2U)TX0FuOWEEkL$76|Z@CtrVydQR-3*fO7yYx7^M&0|t&=Ic4PQ_20J_JNt7312EW z8+kg%2r)0x=`bFHkR|D6vrB-uDl_CN9=c2I>52%s6bio}?_Fgw@5ipBn6keEhT5S} z_v>?WB+3-DE$wk3DB?lmn_)wh>k>lyJXCOz-YVVBN=2}fEw5jR_wlHG&_GtTXm;9F z+~N97erMva*(DfWP*G|oF&v(FYL^_l3B)-hJ+qT-9TX7c~qc9=wgB14) zqZA5@9PnfeeroX#Nd8^=9qh-y2ACr}<_`UC9CnLi1K#W4x@CJ(7b>t!k!9}IF3Y>E LT?6^O4fE;$JfE!y literal 0 HcmV?d00001 diff --git a/docs/build/doctrees/README.doctree b/docs/build/doctrees/README.doctree new file mode 100644 index 0000000000000000000000000000000000000000..d2950c0b6ac91bb59546226a1ecb454b425857e0 GIT binary patch literal 4615 zcmd5=O=~2_8D6b+G#Y)3q;+<2*wv;@Vp~gAGrN#L5E!yfd@!=bvI!;^)2ivNnJTNg ztG7NR%^~2BELnxRx&0Rc216jfAcWw5kQ_tE!Qhj@7lZL3PxaUI$c_+84iOA=y;b#o zKJQ2A{mzG9Z(S+=+=k8=PfrIVj#C*^ox9~&MmC|T$v?>N{wDu*zTrPM00lq zCnCm0tZ16Qo4dY0Zn)5c>V8+#$Z(l9*I9=xvF^M14(qv&;YQHbmRo%I`dhi*#_qLW z(o-+CBtFec=}Q@bER(Y>*9#lv*rHpibUJX?1W##xU`NEQ5MvY{Sp!?V?u$IuUe9hM zh}IzDyOWZn{92A}Hd~BHbfoCmpRulM$i#2uY=hlmYwR{#WZUkQA(IImGJ6sYq51A3 zTp<%WgkF01_>G4@fBTJr(opu!{#84IO+9E&CW>UNZS@`8-FY~QEnIa>gSRMADNiSN z1FnO?U{E^brn~6azu*63UbzVR4NLtF*d6Z$_C1)+UV>A)zC2eVs=t)sRGC0Zlo7;~Mm^rhm=^%5TYN zvYaWZsXF$bf}|6RMDmF$Q!P;>JXW&`tE(+@W+3^)LxEtVK;|(O(|duDZ9{_5G$<=X z5TUf)3u1Ya3Q6L?Fd!>a@;y|l0!^Aeu_!SdFrNm>romVWAy1HzxSAvYoCfD$iW(R| zV!~4*hSg5sYfqE0|4%B-((?D0hhSYDn)C#Ko-}Fs0C1TahD_Ad*ldtZgONouSotQs zO3fNh&vCPX+lS8!H}+fhJNES3A+)+(-knP+Cx*wE~ux= zkEx)L)M5;$ zTg|jNRx&j-jdQp34iOgV)Bt(o!1X3HMVmHKW=h7*-=1k zu}!kD0UjJ%5I8W0fkSwP8wCa4O|=jIjFf3=V;N%7!KqDpnn_K=_RRt%kqM8v<|RZo zLJYddGYUg0ExUC>AkEicj7AEST?weEj)h|`U>u$_H~klcV4m`GIwI`3#R&N-9&gPO z5Z&@w1>~d?08#LSoBZv~S6x4&8ERhD6}&NPo-#tG3Vm|87wZ}bvPR?gQ@}u~$uM^} z{K-NAoD2<35FS$ucr@F6`TmdK&%PQ*=h%D7jQuM$dn7CIkUgSmz^NG*GLZH|W)cBm zJwrywqS&x}f7xvVlS$a5XJbHE&X{LzQ%_SvPQzvt&GA~49{OuKAxN|*7J04Vs27TL zxePHUlghQ*5yKNMLg34MgO>{z;`Wiv{Fn>vig#^Q2hM;V8S!)s4Ah0;x-S*lj?SIq z31(ghBV{)FckEFP%p@ZkBZa3>fl)N4Gj}7xsiTl4go_Zbb@V+yLp*a^)q5LY72~q3 zow-Gt9{cyO?~lHmAb$Zxp2i%>VZyTI6~NhoQh=7h8y>KU{p%NF`t><#`9cO6+{Vpf zu2OV{W4qbw`q`@oI!ysDimZUvPllGfLe+^t4N)aVnjwD~+ow>XB9?pw% zXSiJ1^fQvU_Hm>_V!&u|LlMMh4U@It>jwP~QZQt_o_Qm$J-r?5k?Rh;?sui0J&npFuwmv-P*DBte-&!ut9eMEN z%;RqHth?mRp-worKwZ(lR6T6#fv{2JR)@N@LbYP8x)?0A^|+a!{XOuI6ht!`uATQ9 zji7|iFShlFccJN3!=P3T+s|RX`|bKJG-rcq(`(4@cD!&DxUFUlGfZbz+@`PG3vIn8 z(Z%_|TQ1g09$+N7PNP|Jn!Z=@+Mb>YTlIRw3qxnwZB&Em63s#H4l01gY_(P`*NSf0 zX*GhjtB1;Nb*Y7dw(j$)ZN1lTR?1G@YgF8FP(2$u0ao1BJO1}4Ki<}Z^+rv3MQqIu z02t80jQtuwfAa@gGf%hNYT*$iOScx@?^S0W^4%JK-�Uop}WR9(QZ#0YD^8m7sRIbKh7l*q!`#QiTB}j? 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 ijg0Rh + + + + + + Abductive Learning — ABL 0.1.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Abductive Learningïƒ

+

What is ABL

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/build/html/ABL/Quick Start.html b/docs/build/html/ABL/Quick Start.html new file mode 100644 index 0000000..c5791c2 --- /dev/null +++ b/docs/build/html/ABL/Quick Start.html @@ -0,0 +1,171 @@ + + + + + + + Quick Start — ABL 0.1.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Quick Startïƒ

+

How to use

+ +
+

Required packagesïƒ

+

This package requires the following packages:

+ +

The easiest way to get these is to use +pip or +conda environment +manager. Typing the following command in your terminal will install all +required packages in your Python environment.

+
$ conda install numpy
+
+
+

or

+
$ pip install numpy
+
+
+
+
+

Getting and installing ABLïƒ

+

The easiest way to install ABL is to type pip install ABL in you +terminal/command line.

+

If you want to install ABL by source code, download this project and +sequentially run following commands in your terminal/command line.

+
$ python setup.py build
+$ python setup.py install
+
+
+
+
+

A quick exampleïƒ

+

Show an example.

+

More examples are available in the Example part.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/build/html/Examples/MNISTadd.html b/docs/build/html/Examples/MNISTadd.html new file mode 100644 index 0000000..646b64d --- /dev/null +++ b/docs/build/html/Examples/MNISTadd.html @@ -0,0 +1,115 @@ + + + + + + + MNISTadd — ABL 0.1.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

MNISTaddïƒ

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/build/html/README.html b/docs/build/html/README.html new file mode 100644 index 0000000..a3c89cf --- /dev/null +++ b/docs/build/html/README.html @@ -0,0 +1,129 @@ + + + + + + + ABL — ABL 0.1.0 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ABLïƒ

+

ABL(Abductive Learning) is …

+
+

Installationïƒ

+

ABL is distributed on PyPI and can be installed with pip:

+
$ pip install ABL
+
+
+

Alternatively, to install ABL by source code, download this project and sequentially run following commands in your terminal/command line.

+
$ python setup.py build
+$ python setup.py install
+
+
+
+
+

Releasesïƒ

+

release 0.1

+
+
+ + +
+
+
+ +
+ +
+

© Copyright Yu-Xuan Huang, Wen-Chao Hu, En-Hao Gao.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/build/html/_sources/ABL/Abductive Learning.rst.txt b/docs/build/html/_sources/ABL/Abductive Learning.rst.txt new file mode 100644 index 0000000..47537b3 --- /dev/null +++ b/docs/build/html/_sources/ABL/Abductive Learning.rst.txt @@ -0,0 +1,5 @@ +----------------------------- +Abductive Learning +----------------------------- + +What is ABL \ No newline at end of file diff --git a/docs/build/html/_sources/ABL/Quick Start.rst.txt b/docs/build/html/_sources/ABL/Quick Start.rst.txt new file mode 100644 index 0000000..4c7da0a --- /dev/null +++ b/docs/build/html/_sources/ABL/Quick Start.rst.txt @@ -0,0 +1,52 @@ +--------------- +Quick Start +--------------- + +How to use + +.. contents:: Table of Contents + +Required packages +----------------- + +This package requires the following packages: + +- Python version above 3.x +- ``numpy`` http://www.numpy.org + +The easiest way to get these is to use +`pip `__ or +`conda `__ environment +manager. Typing the following command in your terminal will install all +required packages in your Python environment. + +.. code:: console + + $ conda install numpy + +or + +.. code:: console + + $ pip install numpy + +Getting and installing ABL +---------------------------- + +The easiest way to install ABL is to type ``pip install ABL`` in you +terminal/command line. + +If you want to install ABL by source code, download this project and +sequentially run following commands in your terminal/command line. + +.. code:: console + + $ python setup.py build + $ python setup.py install + +A quick example +--------------- + +Show an example. + +More examples are available in the **Example** part. diff --git a/docs/build/html/_sources/Examples/MNISTadd.rst.txt b/docs/build/html/_sources/Examples/MNISTadd.rst.txt new file mode 100644 index 0000000..c958334 --- /dev/null +++ b/docs/build/html/_sources/Examples/MNISTadd.rst.txt @@ -0,0 +1,3 @@ +------------------------------------- +MNISTadd +------------------------------------- diff --git a/docs/build/html/_sources/README.rst.txt b/docs/build/html/_sources/README.rst.txt new file mode 100644 index 0000000..18600c4 --- /dev/null +++ b/docs/build/html/_sources/README.rst.txt @@ -0,0 +1,27 @@ +ABL +^^^^^^ + +ABL(Abductive Learning) is ... + +Installation +------------- + +ABL is distributed on PyPI and can be installed with ``pip``: + +.. code:: console + + $ pip install ABL + +Alternatively, to install ABL by source code, download this project and sequentially run following commands in your terminal/command line. + +.. code:: console + + $ python setup.py build + $ python setup.py install + + +Releases +-------- +`release 0.1`_ + +.. _release 0.1: https://github.com/AbductiveLearning/ABL-Package/releases/tag/v0.1 \ No newline at end of file diff --git a/docs/build/html/_sources/index.rst.txt b/docs/build/html/_sources/index.rst.txt new file mode 100644 index 0000000..6acedc2 --- /dev/null +++ b/docs/build/html/_sources/index.rst.txt @@ -0,0 +1,15 @@ +.. include:: README.rst + +.. toctree:: + :caption: Tutorial of ABL + :maxdepth: 2 + + ABL/Abductive Learning.rst + ABL/Quick Start.rst + +.. toctree:: + :caption: Examples + :maxdepth: 2 + + Examples/MNISTadd.rst + diff --git a/docs/build/html/_static/_sphinx_javascript_frameworks_compat.js b/docs/build/html/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 0000000..8141580 --- /dev/null +++ b/docs/build/html/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,123 @@ +/* Compatability shim for jQuery and underscores.js. + * + * Copyright Sphinx contributors + * Released under the two clause BSD licence + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/docs/build/html/_static/basic.css b/docs/build/html/_static/basic.css new file mode 100644 index 0000000..7577acb --- /dev/null +++ b/docs/build/html/_static/basic.css @@ -0,0 +1,903 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/docs/build/html/_static/css/badge_only.css b/docs/build/html/_static/css/badge_only.css new file mode 100644 index 0000000..c718cee --- /dev/null +++ b/docs/build/html/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff b/docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 0000000000000000000000000000000000000000..6cb60000181dbd348963953ac8ac54afb46c63d5 GIT binary patch literal 87624 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

!pma|lSQ?8FBe{DRl|@FzhU7Cb>&@ataZS{g zrCQo@Lushkm71KyL3$%QD?KeSADp!x{f z=8g-xggQyFIyp&U(+DO4!2ygCg$vPu1pqEc^*Qa)IPstXB!i@fDLx<-```)5UsmT$Yl%a2onC zAFmUqUVZ7M=U;sB~=#ZhJ zS2lbGii8+5IZ#kxQUi*iaRi9X

#R4x5a04mzf2YJ>#U<-Nc81}`=EFMdUjIP>d| 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

b(7>T&1{%W+D%3_gwxcBR7_myM-&X z?(#}8K??iQEr-2D<8PjWn8=_qrW=k*CGBR6GzVHu=Ah?Doqy(N9>rZ(Q9WcG8_39*p#SVgl#Svp*p9=^>1)As3kcu zwYZy2O^rU7V-4VHKCltxU7M#UJvHnkg=u*k-lne-$>#C}UdU)(FHDx!L|p&>QLDTx z0d%08F36ctVyiq-6oAe!2D-EDn~BPSsx3MW*g#`uXy)SQleuijT&zgr&$y=f`77~F z+(FP(5r-cI5?W0u-58B7Aj~vdFYORCioWJNvVIc@9~&_aL~dpd;re){sWk}e%+*9lQwRgB-u!r zP2SvgGLMDm%W<+c;ibKv6w)G+^ZD6E=Ja^>HGb(7>iEx`wFFU zE{I1Gns26kw@2bfTjXGfHX6b?6Y9^uyK?g{o@mosCWTBTXe&D!Q67vi7+rbp@R> zx$t2)UXM@Ub;IBTd&@#K*jd&?M~1`;t>Yo)q$RxF`_T3boRO5OtP`r zC93Zs%kcI%wjE)Gk&Qp9br@nw$sX4J-(_E71L`8+G}5T%6s|pf``b zDMRhlBUz)r*grRgVb}xYdCI3IYMg>U5v{FbLs9Gt+oEH`qm$BUm)kezfBda-!+Hcd zc1Lc*h`3V!j_KK*h0VWyvtz>1DOExR-YBg{=ceD;8)ObIGKZZJc>XW7)wM|KlpG(Q zK__fDeCbVYMs6YgaOn_!&l6$JN$HZA-t8>fA0HEx8W}7sKe%&k*Xi!9<_uVOsCJtW zoYbv@GT}Hq+dae!;5@UEG12IBw~zCU&bP=eTG=w0s2PX1+;v7qUhkqO@)QlzrI3p- zyJ=vi?piksLM#@(v2!noIC$ali_`cug*Lxi&t6%|_;fS;z7z7YxZ}gtys>fwbb9~Z z%Ujk9rX3Udb?chb#?c5ZO~KbBp2;UXV?tZZ82Fkg3M|xK)&AcS`Fe;ZLh?jiUA@l_}BhEg&me1m8SF6ajYBj)nNgD_Z3^WstO{N%E-vHG~^Q$9UT;skRa9HB5QkDq_GE~vCP4O`k~z@Q%Io{ zR5Te)g=4}m7SzJjfCMknhkBKS*4+c){PzI(&8ei#iT>fE3PUpN3sO3D?|E)mkN8&d zOSPNtH8Cgg_eWpa+g`FThgq#%y5v-pbW#>F>X;d*W_=i5V;{-nRBoaA@bZp;V(f%Y7YG+jK=@i~6Y2S)P zUkT`BWLW#SgqR`lTR>ZPg^!DnKYsM!kUn;{IdMbECkz$5{QP|agQqi69}?D%l@WW` zl&k^CZsU+=i+CsMLn8hhv_C)p3NA2$Emv^%MS;M%YVO<$WR0*60HU$4SxpVBK*n*Q zd@7wk$uXmathz^{mZCbo9g^c^W)4Zd)2p`bTzp)BQ(eNNqhs2IMjAsVDUr6`)Edy- z@e`K}AIckew+#yp?c``B$>tz3mksNq;hT?T(@NdJtl3>kWz$MCIXnp&5ZKB?>7Uro zEiY{5yl<)&|M2rfpIA#}XjoJ<>tk+OWo+6rsg0BCj1l8k?3wq~f*KraYiZW0Pgr13 z7^99%L)8RVLxQV;B$HBMXmffUfvP7KUtZZ04@EuD^yS~}o;YzA7^JQwvY1QYwq|`k zFN+l5ma@oxMi!AOIVvgh`^76xWu?WZ9$hed-;tEy@bvVEkR2V z#{rQ;CQKL-k>_Zi)uDL!a2({_zP-1%LID+S-d^tRer?4bUxWu6Sf9_!p(c3blXCb) zc!sOeYySF!3l`U%SspY@(b_8`)i=U4xqWbC^um)c&5Xg& z(bhR3yK`W0{6Fg%K<3xppS8T*9$MBi8*pOvn&UsLSzUJ}B{n7{IW9IC6kqJz`Nh#i zyLT^wq+Y#}j-__*p2`3-6D?)qSpSdi7UO7ID_UAD)o&lqWuPO%VOrCcaU$ztZ)vQ{ zioOel4Nv?!6af*0^B?l!eQYj{!wa4Nov=E z!ZeS701pp^Lc(+G-`dQN!-D1`f>GNG@Xfrw^e9 z4w#>L2&Q98#!bT4>(Ag@JOYO?S%sto@J2RcP`_R!xv9dA+rOU7+2QZKcht%HUrq=a zgNEb|FO~Sm2PcYgMt)2Av!eB%ZBogoVw;U75c?YhCuBtSNf{Hr;>dX|EqbG z8fGqWnv)B$BxD^N3=Cqz=N>+Tuf2JIah}rFwqsy!39wgvyL-S0Roej>%Kih=yY=sG z>uq7@G_YXol$a!TtyjNb>s6OI!N|$X%XQ_#nfKR@=sv;SCc-l+r**)(e%2e#8tCB# z(S7%Mk552Y4O`bZ7?~qax^{iZ+WC>OwD${^?iZvq2>N&1t~`VFRUP;A z92S51k?Pe+e4j^PH>h`EzoLSS-WF&&>-`MZI(q<%8=qXp&u)Cj8}}QuXk^9mh#(4k zF_|xmulwAdVWTdlVyO`ztvv(nNuQh0F1jdg`Z|FPSl0LWZT#xDNBA}*9#al;nNXBD zXfR*r;{3CZ%T0VALct0g!5Pw3e(ikw?K-+?X{B2e*RO>Pw89S9w4ilm7wYRT4O|su3ovjvZo+0cr33Qxbn^R`^xv47qsgPr z&D^ZIuX+eg3pQ<@96o3Nw_i#!8A)PCuXCyYb7y-|+iA}B-}bHe_W1L<3k^KN_36rl z^d6H>{qW)3uO9>ihHPn1We@Q3PjK*9F>T)QAC?Hw>GACXqU}7ZXMJ(x=3Jp?YLtj~ zBEh?>m`CPI@b-|~Qr`%1AbK=!GYU29yQxhdGXf0B`lm#YKtq2Rn)B_J=B_!`@O){v zuAS5HW2A%6AAbXEk!nNCKb2>YOI)x?fS-PgCM{1Awa1dtyRCf?Z+j(0W)f^A? z-j@{{93#@BD}jgQQbpgEu?~2C+(q}Ja`dQkYBuPxT+>&7;t#;TKG{HP(q}10P-%*EZo>Td%q~tMIp^Eo3_AgADW_gS3KF&v}c?DQouG zYRy2pHfljY)5f@4vG~nmiwmiG=VCL<1VEn0IIkP&`_vACj9zz~8uTOj<< zaPoqwU#_1sW1J!UF8q#P|Ffj{b%U^EDP8X^*A^^gTCT6_C)U@M`*=z-?d44XhM;L_ zh44$uDbr?b6xa7C+|gQJ{Hri#s%CY8F*~B^v&7c(wJq#kgjkXYU@qFdZ2h&Bt|s`V zvFq7Asy^&D+y(p!yWzd$o;e!X-MhzVVzIbfzV3hSJWBcIbLUYma%}OKx%k1O$N2u7 zv8AIy@3-H;0ON|hyz%1-^U7Nl_U@gRpV>Q~YddIL+rR@OPyhDY>5&Hm{I(AI;o7yv zz5Pdx>Yq1!1iIg=v^cX*X({2I1Ogka5AOD|r1B^2;Kt#L0%oS3c?y=-?tnEu z^*VW7e5>e*6FU!-4ax0QmVai)n$8hXpm+Z|$nZJ*3~$AM9r`@|nLKa8{C9I6 zXcIdq@n+nh8d`n)cr{x3^Y^Rv?p^i$&wMT3fg4`q zw|G~LGn}o4-6RVADeiQ2$DiA-;{5-D@B)qb=dJ#~_W)0+ymW~K`=2`XsUF~qtJ9oo z@q_Bx&-DQJBrta%G`6AfUdAL7nB!PzE`})(8WTz*+7=H$PpPlz#%#oCN?{UUTb9C< znQ29PnNf!r-+>eqetY2py%0Qo8aEiyDxKvU@Z4%_EJF0A8b)q_X%rsR^cI+@S+=f5mTg&%V_Bxr z$g)hzSb9;iUvV7fEQS-4Mz*A6qc~{2WyrF#kSv6mnd6Xyy7RkEAG$qfW@Nwk?T6=p z>D;2O?yjmXxPSJ?ajDNwX73MbeQ4i}0f>9mIOQLX0UL$^08}uEoA5T+TG>nzlxXH1 z3*aF5OgQ&=3OF$2X6$j)*0F)ar~h#KCt}$B7VKmADcrvhY)R17dBfgl!9I=+xQjZ* zb+ncp>Bbn?B)HPmGN(ZlF|sTq4GjhhWlbmYnX>Slg74!&nm=1c&+S2}x)EfIjZcoE zTZz%Qpros&$+ZPfPG_MV9@M=&3}Rm+j`0>Oyfg5(cq3_chU|jA>1q@oxM(>gtibKAtPRY2pc7mC1{)a2w3x<@2?8@FRFX4#RzwTndj#hhGO$>19%` z(re{$&j>LGZZ1LSd9c^V6xxo;rtF{j>7V(2(+>LWo;1Z%m6D$RIW{yf80lDkfOKqK zbuIsrcpuTdj_4i=rd*Y+7uWwb~s-{xg&;Xqpxqy#NG+*EB@lC|X zh}q-t1-y+a{PH;_IrRoc7WQ1AHnT|ODxSvdxl^D3n1ZRO5m3-`*SXph8??8PVhz#% z(R#=D`Yn9A?zcYpzz7NqlF&bg*?1MfDlU?Tu~v+5&Q8xvT^;A)(n z4~r2rXCYW~Uk70Ssy0}39iMv@UPhJ5jr9eG@f1Wx-Cg)$2N|%#X`s64Y=h{TAejFO z!2U($EtoTNn{YoYuZ-8wN7p;r+-kvT8mU-6S~KaYsd&v+nKK=S@F1;O8!9<~T=XO3 z+F78%P9Ak1%>(0;%TQK80+qi`g96SJpLQKa1vqGW3m}e9gP*!;j%~0EdG>F3uOu z1`Ez{Eb6sdS6MyK+vRYHG*^_SH*w^Lvq3gA5lq#Wz`VhNc?!ObH_;6GE>v;^xfn*| z&g3dfn5c!BiK1_)Z-{WX{Rxh|g<}T(3is1wA%#NX!jhyTK7lo&VSUe>jUxnWW4I zP>Z&4U~o9EPfAGm{=CKaG29BR)Um%e)xY}gI~h&I|bZPIixG& z9oMg+f!YbUKKETdGmjYGPs<`7(2+~gL1Ww3thOjA^d##q%N8A{_H@GYE6-VlIe!bf z-e%-(4K;Fd2l|x^srY*hHLjc63%OicK81j;e2T8^dKxg1W>HqGmC?Uhw9WLj(Ny~- zR>((ElN@^9;xug3VVkwOC?_r2*@GGT#j^P;p|a&hIN zEt{5*hn%gY1wR76p8E>?cID-omRy<^&-Go;pMiXV^ZY?zIVVTsVUZfnr#2JpEe15~ zfI=ZyzMvjBB(g3bvX~;0s;Y_14CSsTLh0VAu5}*cSH}0w&d?v&F;|5@uM`_mI1&N- z&}ET7a3OGk!n6w%2#0(m@8bZtOfmOh)Pb5dndb$^rR5M@l<|83-l6jZFjeX9?PW;A zLsu-PW*qH$2t}#RcQwc!){}3a2<;N*=i(bNUzY~@IQiT@xT^A$CUjUC!7q9r-A1MdEC0Wx;jQ)!EwH*4v;DZ%<(hYwOiK9K# zlI*yE) z{%AGykx$T=_yoNG{4sN1^b)+QLc8@P&`F)rd(c&5DC8)DP~34G(0&<>cwy)=9fzEj#-E8Vp9zvS_4_J6+`Z{1mWkSZS?Xsa+K0=>{ z^?tKPeFW?JaE;yz{nWL$+|=l~lmps^j)pNwH17#$4yNxBT)2j#@s%i;OX5i2e$j$^ z3~z+?Ot?}8x{yCVxIeYv9*28CQ52e1PpDex&ZI=4Pzh?YsWK^VXdo1UfMXmVNaG;+ zPIgda*QQ({iG~?}Z9m?ej$Wb?2Jt3pH5hXGY$*)P& z+Cj#G?H%-nZ6m3)HV+MvN~hqyHw~9)UY#dz%z~Oy5gV?dm>|3TNqkd2X2nsD!hhk; zClEs~C2{W9R{SH&Ry?`}m$v3(k799aKEq1P_auC&X^XEDSjKnKJ>A*NT$Kv3`yNxS zs}7_B-x6H8Ka0t7xja~=?kk4Z+(68$Y_WJf@tmi@Z&i+NT+MvXavf}ji#ZnfPp)eW zz6Gt)RjY{eWV*V=e_hCb^#-ZLS&RRZd<6ha6&*FaD`ed$u?Ll2f-<#$S@?lrM|4M& zl%B|3v(D8U_*s5sns>s*J^=tvtK1ebzGKw@=O8zu3tP~0#XJ#YuQZ9o+Y6po@`5!d z|0H|O*XcF*k{YvO-pBCY@m4xJOw60>)wUzm5|of?DvnXdvM+PGT7q!2+aKGTkBQG) zcJwj45L#hR<;uv8W|Jx77w|x01tw;%i%FP)X-@ijYb{)l%&>&7i!8p5qrj_Z&V{i8 zBkr8|xk$*vHlvvgHZ&OygCi{A@yBT%>Hd7SpnW?$(5taUd>Wh6aiue3F-(?c!mC%q z>*xp>ytUl=?Wr}~Z1MU4p2Qa}zJ>~@abxxxma^9H`!)O#j(S+L=o-ep!$NB~(7(hQ zUTyI;3%|evv>#~=l}xRnl0qsm6NbNMT$BKggsCN$Fyc=tYyD;qH^Ow~23kKQcQR31*dmS zao9z&XH+z5BX=WpQssjbz1 z4>CU2A6q`x(R#MHKf9=RIXJMOKWq3?(-wax;Jx@xxUF(?R}1sK^z)PcYtQ$+0~WKs zX4ZH2FUo9lbMsI$H4Et;jF>JA#6GTUwRk>p-3(DM+Rt1SySOpqd5;AjEaY+a z^^pYVVR6N>@v-4STMmU9Ijphd@Br?`XFrMS{DU;lgb%(4YoB=JVxg5L{;Icdnqghb z-${HC_;e}+{EapH9(S+@U8fg4m)o2!%whVD9_$~sd9A*|`8j{8#p_88YYY5crHOc5 z*H?DH8Ak~ds3Z@A+G7#(nJlLbk}#G%oJb3lRM#&cs*dxAOo8im679<6qr(}ZO>}3s zCEHneH(npT;d*X*6ZzIV}Pr;0Nryv6pO{+>F%tcD<2mOEB*v0GD1y6d=YfHNH3Mt3gJC!imOAELwpqNNIC=-g-q)>Qp1T0+IiCgQm{P$e z%`eIQ^5x67F5kLkQ{!+bgM6(FR$DT70Pn#&VOQmnTK1hun{5RW$x6#&yHqm#y8UT> z#iKR+5-tJj=uFOJR#0EG;2mh`H7+$8?jqefp}jnZ}O&Rn&?YJvh6lsmN)d!)cIdr9uVhWMNs z5B-Q6@G`PNhx&UQ>2{lWNa!MTb+(a_SMNI9sYya3_K}Apk%VbBM-k3OJr1@(V+&)F zKT}8InB?UK7yLH9kYKFCKuJ#s(%ce$$addoS7_mDLrJXqZa5(W^nWq@W!egDr+*@DK#C!WQN^e9Y7q+bx zo3Y&ANNFmxul}UEo82S65$~(}!kn{xbHAWGlD6hX#}V~)u7;`tf1RTvDA|6-ysTK! zU1KhVdb8==8F7Eg=3gG(XOC2mlYDgo3<+2vl#pXbyN)3m+2Q20|9u+AmgpF;6SPe80qLtPztEU7SbsVo#)=do}QBVl?Faks`pYJU5ZW`pr(N%JCabUrP|;S9Fk`io$LyJ zlFr6*6HzK{iE><=!1!I#nTTkFm`3~)p`fp#4Gp3)JhvFy!~wuU^uYtV)!sK_If{fj zPSnwAGr{*|tanr6{PlKjv}h#wZ#nl5^zP^*bAYJi^hyv;A~Q;AU6QeV)oXKhN;l;EcirU8E$bz>p+p80ZDFIU z(oM;DRj32JI-5y%S0||}2Yy6Yl=t_AbSFA+?ya2iPGY*_eQ-aWZ&`E?^fR#y1QSQ* z)7?g7)4iC;d$%R;S-cRhr#!-*&NfGIi+UCZ9GN(*Eb{w$$;S>^&&%%As zNOcB*%`E0~;b`d#5E5pTnKW&4V%xCq3Gg%%9!SY)?nWU=P6G&{U!&pk&{)uIImNlV z@~2kL=~4IqUc6-PZYg?MkKd*L#Cn%Ly2eRf`xkzdo|n73&!Xo9mhc@kopP|7Nr98p zeOpR#03>jfe19f+U0q$vx|Zqdl%RWksrPf)X3=@#Id@RzX9_w=j`QG+KAY+c@DS5~ zxkdkJY&1E%61l>REaoJl5xvjHw0ah;r=J(R^(&sUZX%NDMz~aYFhO1YtSiWqWBByOF4fQy{`YH4t z=GZuwq;hPoG5Fx)&<7H9;PbS1yL(Gk0UKjeG|jiV>Nt9IQ|ruUIA=u^wug| zDQ0Y3u3OCH&q7G}bY0j<@rcFWU3mXo6%JIU4K9x_3-Um1G~Dxeoc|f~=VzvGPE1T} znb@MMxeWeXf?xO8xT1z%!aw*#@wYrq{O68a{F`&-xz*Q@&5-EP$`y2+*b2+!k<5kd zFj(}4FgPq84G#XeakOOPi1qYxYaM6d5AiyR<&own8DXkpht;T{B;6A{~{! zrK7Xko9QH83R8*|fapOv;mXD}dhRV$15LO_3D<^Dc5kcROSd)jbw@NKu}$fS$HwG`$o!e}{w2MnwIQ~Rw&@&TDym6@R|w;urUqVJ zZpm*JK9AQ?ETN^Tg26(t7<$x!cGKVqIWG zaRKRq)&h{E5R8;s9X1N_ICR0(AWc~{NT;yN)as?{$x`)5JhQYct1@ZDGMdQQ*ORJD zf;hiXwpjU%r~a>Qn(W(!t{OohHC9oZ>nJqh%uL{nyhq9ePUk%uUgcvJuScPZJ0Djq zTB_1Y)$k+!#Ny}ZUT3ik*34|pIMXztSxs9spTLXpopiDVo!B!jssWsRq3U)80d3?pYFC@4e8B0v2)fJhrZ*(St8^#-w-Z?Skd=^O+| zt%F9Qxe)pT6flBP@JXA49Z}kPN$OXKn*GuRpzbksn_Yxsa~MbeCGMj0lHx7WZ7vrJ zK1y_wz7>w7z&JPvGlDaUjEAGl$&DyC>RlPi3PA1@KaFKI6~ccSD0=TD_^zLVPt|vh z?^5oXL&0P6R>0wKD5!T+^hi_}p`ul9AXN0f+(4>^bE8$mc^mbUA8N z)R`*gB(|uUQ}xy4Zhynd2|o_6ocjgIjbcb#*5q(IL3sj`oXv#E`19lZl*Fx3#C#Mi zK4#!uW`8VJi<*?arWv3F6XGEBy=ZRsNi`7X_ihb+uiNlOdh=)K2oD3O+(CyQH0hGD zcjq`_k8AGZWPUbcV?%u%7O_}rAO(ng``~cQv@?)i%X7f|Z;^zvB zpILZ4-at2gxuMQcGUCcf8%?!H36(dWu@>FBsZ<}crmd%lFX`3rC1G|~nQl&lG2$)p z32M+8Phf%dYBUU*b72xdoiXu+Ny7DFqZ7^*I1L9YH+CU1n%;*(2`xut4#R^WeOJhX zkb^wr@_NyL`wk6r2UqwmMdqS8t3s%&sc5aBE*_w%w7O@7#%?;!nEb?Ddan9Irsi)K z;eUm}&u)e`cyZ+gU7F7p zlxZ@lu+ih@Nc@#UUj^^g^eI?hPE~vzN?E2~-NRVq6?4bpw+<&k6 zR>I5+I%zt3M_Wrk1lJ$OaIdl8K8SnaMfCO9Kvzrjb&8G$Yrn^j;PrD~r-^|p^$!e_ z!oa_^x-OVaMKi(a`?rNY^O3o^U}k)d2QoJEpNx!m(06YSW&B7mtFEnCV*0x;S>GMQ z+o2=lyT`2Wj)PuVnoZME``y2%zav>)-Wh01tA^(U-xX~CZGqVJ9!?XUoPK!v})V*u={hCY^jcl;ruuBjM*H}_Ql_7y`PnD0zI=`}zU zHkRr%OeeuDUX$cn;~#}O@}JP7p)Tv^hG#Pm$k2EjefP(qtp6*}(cZ4sk{|1m`Sw%R zx5x0A(73?2-?zR!4qB%A+rjR6-^zOH+f(pLXwl!U8lDgLk@UB;M%OlxhU%PiA|ljh zGXqC_JF;W(FGAja3WL$_uk4|HaH_cQCe<62f;pue@>{YUycqVf4% z#Cdcm{v9_3cUL9soK=`cmJTxpLwg*4`yrX}(jx*}L&~zqYNRFrBaK_p4L+iT-a1*RgAkuf$gEZ65`tBsI3eKRh{u+4Fx4xT&H$Zcs z6XADe9$iY#?+oR93W@}8z;{yL$zJQb6Yv&zCh2T{&39%!;_rx$Ex~#WCf}W#r8#)D z-{BkZ_Udc(cjH6hcV>oN>dbwYp$~h(4fLRa(RU_y@pI;!g5>Nw^$I$rdYhB8?`Ht) z!?bSkcP7X2cA%A`lh5F-17QDT)~zmqcjBFg?Xy|u3Krt^h~S;XbpV99Ere(0D{^qnf(th@IVyfc^`uzIBS?)@|CyQBL4 z5wx#s?{e8;eRl#r3`geQ`SM!py9e=VcrmS?Zrj~t)+GKmXMKAbJ_>a6j|>vj_}l9B zG@sA<_9UJNP+Wywdxca>bTcq_ z%?$veQ{HCo8W@I=+lZ&PS3dy^&KR#cpDq;asMO`r<2jUGSok$%zFK3q4&~B)N>uyh zVOH^1M`i8&exq`UexsCkZIvDpA2$NX{~>RU`4|uR_$(mBJ!$9;SI}KY$(gFA2!y1C zB(1Ep;8K$*03mS&c=iLZ$5Qf|2=ROd80ATEWDc0*brUXT;2?7{Qr9)CZ|XOI7t32> zSgV@?SaVMUpuAkr!1z-HE}FtdG+hTE{#f1=!?_@&>0@)}DEF+%qx3)&jDbi8d?{Tp zY~2S|>%LOlx{u($4?w6CoqrnANiDJ0R94oZhD?{g1M(>f0fM4}rXXz(_lQ{Unukj* zBaz zgCzNyKG9LH2uH$zp*5@bN9Hb}Jrd__QQ!3_Z_AN%chNgXLy5ARsD!C5sQL!3Fs!=~ zuvgk8-{msH;lbYSa#y*twYiwbCf4Y-$Mx7L_#*(6Q?YP;?xOo6+8J8XQ5@C4zMNoh z1)$oNh2p^!xs>z6rE#EC^`v{Yrf41qpqI<+N-H**xw*{N(o&AWMWk2bo)`yJ6CxzCPc$N$EpMRcKM2Z`(BJsUe#^Q=zxCc@-m7mR_{N@nJKjC_ zL(1pwMCpto$U2W9IPq}`QaXD*&ZsX2tvBvv7@Vbux&zV5W#j$5*o9p~gF}OUAQ!lP z?z?=%#7wUzJbxA9d7kcmeN$zBHwsxsP@KuHTJMC4j@JeCk$6oUhe21 zy;-!^7jwQVae_@yaW=)ct2gt#hEE{;?+x*v(R^w-YW@H<5y0X*oyUApTN5D)J50G7 z25n8S2YUt@HGiJb!?M1U9ya!GIlPm|&U(?0DQ~&vMsk2NdU>&LA-aJ?PhiXHHJLW| zTLZ!R=K$6_R(_hSkxq0FH53GNsCFBC;rUbPu3Vg6u+#7SS}qe|7qs#~_|`j4GoH=+ z_&DkM9{|9H%39jdjzFkGjxEh4hQdDg>f&>+q&G#mrpKJg7v4tj_L%b}GmAWZzHF=> z6hlNucy>R_oCPh-<(w}Z*3qtz(^1LIi!Xr_=2;%GgcmpJwA;q0zKiB;|CWK(L$GcD zpnU%NoU4L8f;C4#UAQ3{8=IPpP4!QD4gXPmz_Kf5=GH<7bvI0};!^fRnX&}pwIrA| zYdN#LgR+2X*K*M{jMtBhlsHfRTB|?c+wtjhKPH|d!)&SA14EyI6VpdfFxr6b$YrGKg18bDs z-&iuc2Tks(cm&2sC&my(lbyM}U;=fJDq1hg6G%hatZ`{0rL`^5jA=7hZ6ghg`~A-h z55M8+=e#_em-g=Jw{HA$&$4@Oe9jBQscOr<@(?y1aK7-bt%J8;6^%?gdNZ#2ufdhK zTx~|G{m(Bshpv61w%3zzPf|_ms|_99M8`4!(B59EiZx2}Yz<3S`TWw=wy0i}&#za_ zA%>Nz#-@twNBPZ~dQ#GdFJnL1;0xN3ahXYW`~DJnykDpZptH`+<~%TJ)ztZnXdV=w%#`hL)QotG0z385syxL*AC4UArbv2O{zue0_3zp4NGRsiQw zlTWafaDFR(zv`p2iXmg>tV-W=rl>S5RNMopIz>wNjqYZ$JL9@6lF7B^tXjBsFfLuP zEzsnw8UbL(!X73BbGKP5)462fPW759b1Xjz{ov=mP~DB+H8cUybOivcsw_{sh|nqT zL?W}aDDlfl?}RdMJ<~+j_rtY#FSL_QGf)&9g%dPq>F?|AY86}rzBB#feQ^SxQ2^sg zOQdm?)F-2)J3)rMqKv*v-^!0Z0ly3T2#>b;q_EPX=ap~UyCE_3Xj|yg?KppZ+{#~{ zWW9JB#RB5Y@)~DNI!aDiY3n7EwQl0`QQrDDt-SR~)USAS(xl;9iR$s(94lMBtFsj4 zs?(!QOnbjY`!V(pxPKwqP15Fh(f-96+6nFoXkUuAF$}3!A9tyT<%5aPo~k>9Q2ZL+7WY+AE=2TdQb@k^^G((K%oAfuj0+)4LDGKtn~h7QIh zdLmumd>CJ9c%#2|B;El4rAkq72HOBYv($zi6R|&$>Zhi-t84v> zh9=`-1gu7T<7)BwcyBy4#PJqrCH-CJbL3nb7dqHGJfttppm!2^8_D*Q^u=CA80tuq zgPU*jrl#^x>ri=cpn-NuWLJrM=kDHxEAqu^o*vt%YyzV4-+jA_v^rqRzD7(B)f8?mm%*$ zfoyU(=m?0Mx(^~l!Dcd@v$oV=5Yj0CH!qhHeEpZha9IHVjqH~ILC5q0bJz%?bKzFq zuYcX@RqbsI^Aem%52;%tId086g1&3CL43s>3O5#VjHXaidEZ4{7hSMr;|9`#iLrr( z#-PZwvEInq;J>*RKa9X-gdY`LDSiS#eI_P1j}^GXwpT9Px?z2HS4ah$^aCo29wRdH zN;pJC&NWoj6$};IGzFVB(pat)%SMJujW!McyXUl;7{hpNjDhZ4yp8te0^x;Nv!`TD zSiw{VhT#NLcly77wv_SF#5XM;Z4y^NKfOcS?iq0tkJynlewpbt7y4r{KN|t$nN;lZ zPmE8X&2hS3%KF-(QbepL$PQyk>~VCgZ8SXNyQ=+igW13fo$?73Kj(SlZFQl^(#;)P=-Bq zI3hO1k>v($=JyRY#XU8e0QgH~kzh9w?3Q5N-u9th$^mLEFyv{_$umT8M-05B2KZ12 zoP65qZm%QqX(4)tnC34qxdNLu>P^}u9T-9`NDvO}QIZ6ZIJ>E4h2*o1#G`*qzTIyB z(kMnmc`gRNcnE;>I)X0^{N!{}C}mxIMlFtGef4hsVuNEn>Dea;2hQRpb5(e2rC308 zno&UyO5seJ#@g$EAt0kC5haz7GvIRf2zhl%fSLxxFp-5~9Z^`Pqq2G4&!p$c0}K5a zqRG&ldId0CrEfi&ZQa+~)j>Y1D{&cHmWz7ZOjcj(e3CyUt_%Ba$cLEwIi0(CWLQQ8 z-2oqll7mEuK78gOH&Ggco$j`hyXXt6iG67~+B3EZ|DS0&zRt+aPXb{b(cdV>Ca285 z9-lXfgr^&fC}b=V=1TixrW8A1{REUsMChjmUj({!w>1OM(A%Zy{l|)*%)JPSv&UaB zjVO+eD3>MSkq-0Jurl=vMHPOa6j(nb3ge$uR#`Iwm--2{V{cw?(8g~#Kcc;Q6Tgh_ zjN>qW0RS(m6x-X1$dO4pJtA3km{0_*4OxGO!slCn5*XoRf6@|tvKRo(^Pe>}=`$!e zJfHX*6rH*54z(}#l|F9#Z1zli2RyrS?9%P5SQw?=BJ~p4DwlcAMHg<_ykY$sdTIfW zPnPOfL6v&0pGN7jbf(7 zvPAA9AcuYRn!18M!}Iy#UMLoItP-hdFImJiWYS}SG%mQ{g3B+s{IW|f-ch-Tm|M42 zlhdfl(f;1R6PEA)nK>2nU$FR}fxpEY>F&z#FN~kR&@?gagO^ISU-92Rf7a9^8~xBY zB-JC++vH+($mdsoTvL0TOKOkJnZ1i}y#jz%_xx*)>(Z6R#jw)2kghads>-;&y~f7> zKeJ+X&V5@9%CAMf2VNZN`Acy<`B`OjpsC21(-Cy6PU$!U!I_wfaW*BClyRxxxLJe! zIhB-^_Ni43L#C<{r}8&M3~)RFEd+1_vVmg=N<|9lMTcz?`N z%j01wzLWCSoixMRa6iqCTjV;TM(Twk=2;;>wbVs~c}#@i7B`0v!~?&)_3HA=I@v zp~h?}ZU{%*^EPkwyq$r+GCgk%$qRK6wr0})Cg9AZV_wY-X=Hyzv{4Htb2c?K*0t2PXvkq4{7OydZgcluNwCW%XB3=Z*vnK5#5!RY zf@f$|Ueu=pn?f1B7pKU6NYiXC4H}gbQJ+hw_buvcPS_Z0zH=ht!NjnxB%Ea<>+X%z zP0w(WKFNzQaQh@*0?$f)cl?*i$Fp<38uE4#?x!3@L)SHCv={h$qIDz`VFLnTbugP@XE0#I~R z1?GriI8}3AIZpWEn@6CQ7gCm`KClQmF;7QkbCY%M7s+CGXj+*L=-$=z7YyR)i$)7&H*P&AUIuz&H6)c)(;GghD z$^~1PW)qHEi0Y7TdfR>S<`x^;cU!cd#?B>a*YI7GOh}vduy>nH`!Cb96At)&$f7=J z)}7t2E2iG`o&*qIRE4-#=jTJ&{}^witoNR7eKXY8%ID`FR z_<|nRO)B3*L50tXx)@=?AmFf=T|`V{62q9L=SWlJtF}%5*R(Sh1A3}q)&;Ep1KTr zh#ER91_u_Qr|;ZP;+!;ElPyFC{-g7rx!b7^)yHGvft z9KcHHfN{S5DlMzOH?mqq^nW^()sHm&x?gldsgUP9aJ#v}ew5IMLQ?B=&ey7}W9{1G>*>NaY%33!f-)W;|69xNQNAVa{q=(of4|00UQtth z9S5hSnITt9<41!Z0D`2Sy5vcru*22p&0kyS3Hi`qnR=>veNhhFeHm}H5240SZ{Ul) z)l#apymo;?X7e_C#(JAIunSP69>q(&&3fQ^?zK-~EPE0odY{GD8T=AfC`LAbo=k=LgAR{@+>4KfW0|aF}8T?Wp`T|5Q0HeNBtKIa3=u!#BU^D>|zE{PpPNZAs+yLg&31AE_RVADX8Lxg6{* z#6#NCLA7EanLKlL@ibhGYe+7wD7~~?^uqYAHv?KYo;;*b zf-e`6i|<=<4gH+N`B&1MxZj&c1-8psF=iqlLuej(!mdjtZo)v5N zlF;jvE9Ttd3=|-rE99qX_d4h~@m?xnv6$Pd6{#sDtNK7zb)l>_ZzgGN-nDrb#cwXy zlBq-uwKDsmC9{)Q#!-r!c4Iy_ik?4$uGfmvjU^{0S7WXMt|vWL&X7WRq)@gL^FTXd zI_vmZspA=XSZ;5uUxk{OwS12yyOYoP8oajhs?As|?7&=p68)UkHNQrJYVry!RH)A_ z>DWxHW1%>q2syu)o3?c>Q;sCX%XL@D%0(Amkg0bil3{%JsEuhE!U!D42HX|hL1a62 zw3eNe1X<09Pfx<`&+Nv2OjXrCSeT39leq#D3qQuyfAMDL2`SKID|2n+jigrn7G` z8oC_6_QZ-5>(TQpJ$mq2EmR#O~t#~)pI%mnncU^UG!G|y3&+UO+u3^X0f{Ep#ge8}^Jbw?o zu=2c2xuo`ySIEbwQT@X2VNXanv21o)vUvb=xRq{~@iFG-)}itTx|mFaq)C*@RWcEg zUsou4TuDFGswS7q?}dE6fe5ZW%7?T+Hne_dJ-H(z!z8nThA=~~J}on5$?SonzkvHH zckjHINPJ*j-uhly- zxe4=?VxW6|YERPX;OF%jS^!@a{OQH_Cfz;yZD^!M4eM(5=VvULo_O{z;7yg+SFo;l zIpzzyv{>isq?+7|#Y!y2I>>u<`ROJ0Z9}kcEtwjL?s@8!SLg=9lMAY6V^8d7*l*S_ zV&1Hyvz{iaXYJud->!4u=lpAHg*Q5~!2YeCvEQ*_nBKADGyesZ=bq1dHtpv^{@Ta6 zjdx6*#~HV&`ev$^wB9}+!u!Fee#T4JO@?k$=4+?bqsiof-AA=xHSe5+Z#w|Zp~}cU zG;ZG_sfSsQaDMIE?)xnM&fxE2gcIyR57tCSC2rKR6?>5ZWw>uvYt7SCs} zf38Ze`zz6tsmI;eCCsCT zbH+u5QsJRcIQxR4p}ZxHTp|tqL^?i7%hH#jC^U1P^u+k9kjUfo+%Itr$)gS3T#Y=) zWuznVa3C3S8r{b$51LKdV98_dXrLoUV>*mHPQU32~&q|6&_x0B3O?^slCgmwhZ%$qNd3agn#d;2#=WiZn`FJPs*pYTo6If*i}tCinVgPreNeYK2DMw-!i_1p52#CWb0FXN`61I7}MIIW_7Qm^jIq^sptz zlh=KnK<0FY;&i%IG$y zyb9d{)RAtoQ)5ZRk}>Wx9p;N|(&ft**`$!t1c4Gp2WAzUyFSCYr2@gFtPaS}2vok4)mR&o)lccFVsJ=O_*(Er;4V)RDx_+c9 zcLi|4uU(*kmr8iUz7ExUsIP;S8}Sf+YpzPYDPu5;_ok%Uf_tc5z9uh%;Owb^vv`Z6 zBv<1Ri=H$1Iow9|P7|m&PR0Y~I9-igO)WBCxzyA&f4=f7EIKKsKDPjTAov+{XTvA@ zU#8wsOFzCDTX2Zr_oHw%e8p*gjmr;%E8L)9OB~MRp&^=*9M^CJaqz=6^iv%CYm_aM zhVE*4yJAKnNgfWFU7x{*g~Gf~(;5WlafX}A(s6A!(}6`FtX0##!z_q)cV{ePh0DA>aH)4 zCz^#-Bk{o(5Tn<~{h&IrDSK{qHtK}uM=hRDVhKlrT0Zo>RjAyRD3zA70Y3v&aWgf>r&E7g|@qY3--yq(zv1_c7)^^55yYO0P;x^}) z+K}Si#C?l+S#+M!9iiKvJ6vMT6f_r8+GZB`Uy9kGr z#Z0DZ5fPqC^;*7NbrYUT3D29t{skYz8>o*@5gjZeCm%ZO^G0vdane!Ed?T$TV{wl= z%Bealz7XY9!QCO;NoXVaDCAH?(-BC53`+5(Nyv#o26uNd%xFkMC*Y8xd)T6T5?A6u zi*7Tp@$u394U6tcI1PO^-2w#B9nR7$J|4RN!J_*NeiFCROyc$Eiimb+G90Hi4Z=g0 z33m}DMn*<9jBKDwf_U-!V_xLTEnd#x<#Sc4HziyVKTbShss<+#&MdZKbi^H@OL)81 z;_VcC4fn&#d%_I5$*LTs2 zXo3-AP7TI*^)e>8W-)9K6R(7rc&(lgZ0&SEpvgz*0n6vp1>zJ$3p0Vf8k|DL^_*pYo z^FIE5Ypy2I>;q8dojn^gl*rMgBuAgw-6P}O1#A(Xi z?$?nxZPhDU3Pix|puk1tP7yBx*nY_kYhnFgnaXhWbH;$atm8Xmxt8BE#D}68MR0G3 z;~9`6esrj_rP*hSJ0wCRodV@Ja4?w^>6)G&z&T!%O0XUo#vvTk+%z|PJ!yW%EPf_& z3UAHk#|4G1dIJ1>%Hn4d{u3G(;ztrcQPKJ1=jRcNpEHc%HnQv1qOTI3nBl3$utVi9 z!kj)!)(x#&vAn4vWRi@lm`8c1#p4;gYwl69t=6F@Z9XXx(IY;SaBt3J0QvLT9Uev; zUOybXdX0|6Z0CvXgzpw)EVJsWn{@E`1c=ZA!&=Go;cn?+3-j ze=tSOVaP(H5NIsLoO#deuih)aDn4q-@FCVbH%C_6{Jjv$D74<@i>j2`3M8ZIaq$d( zpCzM*a0D1!QrVHU4>W5B!q<Bn7tC!D1_#yD=E?T0O4_zM%&VYdS zb04SvZC2j!L+r(K7ung`VqPD&9Z@&4MjmEsTfNcWXVH8H{|hT*^9-Tl^XYaHx^0g? z%|S~`%W%uEKFNs@a>V1lTz6W0oWX169;Nz~MdLc7ItNAg{9k?*KrpJ+_-#DN8I>rcv7=zj-R8f& zKlCx*NBqS7EhtBL1V4;#!cU-r?Q=hydoksK*4HtWkuz+j$M1_%P!~)gUcOATYVwHv z0TUO#H=cbF_b$d+=Z64vu4MNvR-9DYq5cZMRovPYlyde&LvNDq#U|HW<57HfP0u{S za}z*z&pcN+L9~f*2p7e^q+K2@A5|2X)c%^DdBl%&Q~Zn@Jp3lp$2Y4-t>SDkZmbbL zR9B{X*~GWRb!9&cd3oLA#8I~hj!}&x>h(%EHW(aigXwn?^n6ue&sT+TFz5_HyE>l1 ztrXi6l_cmch^4p#te3=%@8ze7k1%fhV}k>KaDF)I&Id=I=EKhECs}>e^dO#>XD@;ABR2p{IIQ00zcdJx>KL;xc9!n1wS!8o0ERu!t_BELGOKsAF1gq;Ov3u zlqw~&E4Eheb*QGHrpGGI(pgp8V|5|ebv3YSdaRCA?{#;Gzpbt3##uQFKsg)>)^is; zdL)PZ5rGc1r6|~?+)yaMo}`{TvzD7)Db1Op8u{+pT5g=BHK6*2%v$aO5Pr-bF$LWP z4*SwY+=L$YM3vn0tGMGl=?SePKN63`^JXs!b>u++xTSJaf1XLC>$(HE(}{F>19x1P z(=(%@LF*2e&XkYIkafi1B7kc=bG7yMFf=7bJtMs%VOwGsyIFUx-MkI_xcVT!k6#(j zMBQd+z`q4Wd8#>-$kCDQ$ej)h?o||0pq$C3fyTkm)f(d0H!_+On(pDA;a1&+xvt|$L8zv(^vGuayV9=_b1RrIa~3LVsKF7%Iz485?@EQubq?BM3GD(e9l<)Gn>L+^Z| zSMP;p=z#%>B=+|;HFA)}0&^72CIODf0QUj&(N)Zy)(a)2x!U#`E$!`XY3Uv49cbxk z>F(D?&|qJwKHoBdYc-m+Yd8&%=v%+B6xl%~Geu&+DXaC&`P$chc@BrGpZwLiOHTaB zpJ)TuTFpd^C!-|_2F*(*et$PTaK@NUG?Z}b)x%WqCo+OcWW93sY9jKHM*=7 zvQ~5j*-!0APOUTPAaVqOunz>dO1M)JiI}jliq7S0Htk#+wC%ewmQ`7m10iDY*N81; zEl3RLyJGf>Uz}xo-}IM%`C@Fnj%|OidK};IhI47#X0nR?)pd>w(BI->+wug&B|3v@|rk`xhK(4vg2`6Q;uiY3h;1~v+fpYNYlKaUM z_;>&KkJ}%*i8a0CpRn|dYJTgP7ryA+hhNQSW-ryE{?2T5^m~P~XS=FDsovi5@WVdl zf8PDD=503UUr@b8P1MeDfDtpt0TmR*@wxw`D(h&T1GO@U8yVEQ(Am~l&rvVV#tjU& z`O#bl7Z6;WiRL?a)_e!b!=E?dA=hQ>(OcwIwLR=%#PqNydidXIdh{I=^|CM3n~n!L z7s_>chbUROLQ@h^;M+Z&Q2ShmN#;meTPER9ZR^`k)A=^ErKYv~9wwebKk3mB zPq)FNZ-}Cj60og_@IY%><6(v)M)#RSAUq5uJ0y_qNHU4&=4jJaRJpGd;#s9-_i?L! zl-6md#-rci)Agei>+J5*Y{;Z|RA5{^3c)0_s6JFh^`RQRwCY1?ZSK_Y^_`cl4@E}s zNde>HP&2TU8-;750#IW}Vcf^AgI?y^Xn8>b(zVIClf&x=X&t@YpsQ%@vKdjH-6aV@L)xUT?8xc^d_T%SEXU{gB zyLYzwH98WoW0u{~L}R~`zIbq^Qt0XIsOMZTM2MQT+K+7 zW|*02jFa{y9ZPSByT+?&fmxUKS9ltaE<2RON^(y?cS$4~4w}YQ^^Ob|= zzJK9`_~r81v&D1kqWhA3Kr^YJyMuhQCdGxeq+KN)MFLXD9n&s|5+mYckB)Wyzj|7* zf$$J_!pmrVcsn&l%gDQ5fKx9$_fOCI_IK_)_n*(lt6%;6>ieI^R^IicFW<>lKd<`! zBkY0dL~s*5v--OH!w3I^#2UKsxhE+MA4tLKsCi1M*><~%(bLi);bSA-TB&~YU$R8-g$ks`}VIn zcOGRQxgEc8>mQ!J9lv$U2c4(kr$zPK^$$Ok|MX{a4?SFu&0M3z_tLbAT&{Plb~c)d2rD_fU4Q0C?JCU}Rtb;mzLE+Y0C?JCU}Rw6Ncww~fr0be{{{a~aozxm zpa2$W0J)F{rg+*klw*{n$r6U2FEcW~8rx>Id&kq->8fgvtsb_q*4Q{>&)T+a+qP|c z>&DfOIFWqMd7p^P;1>YUtO2$yJLMXpGM!QG5X0mjGK2fsVXkJbd5i+PpMg@ru;5p6 zZ8jTCOV*pOlAp_dme_3^Da~Zc97f6p21}97moZ$Xyx<66O!`)Z0|omHy@+Q8PRFuDq|~UGxu+Q{B$=msO0D*GN^*3A>OI z>B|!H7a7WKfb5~4Z&aR_(qA=uN)~g>Zlb|eY%)7&<jOrL|QrQ>$#B|f0 zTCLep_Gt>;W=?X~Q|qfJx7U*yCW%W11#TH-uBWm~CF*~pT<#}dj#7?iFhSm7pzp^} zbB+4?g*4?qR=xM|M^NMplftK{3#Ti;@5!)zl3%+QDAjY5{5K4A3&=D_CBK$MRN58H zvyBwn2KAf4Hf3;p@FFSp7Mkso%nR-%%d}^bX~6<}^Ix+~HEZoFB!WAYmtnnhR9@;y z9wp{(qP1J5e(q$5yv;ZtCnjf5;yz@If0!|@kO^`xOXXVD$XsQsJsbo6bRD_S?dnm+yhke|p7@1&DkLR=0q*9FX%Lh@Y^!@^urWGHdBjhSvZ^WA95{YRR& z>Ri|4P4)f~6|PC&(jq;t>)~Oh={t^w161b|jnTyYtCYF{RJv}-@0H86uq6dylWKHL zCRJxvSjifH4Qo|zPPmM*zL~gtnUV4Vqa(fP5YC}rxPx5fQrhAdQX=otO&S?#KO@a) zFDbK0ZiD*2NEzvyl=URSERORj%>0k`MXLQSwUWwgnLtPT65FLE8-nMl3!dYs@Bw;< zE9ouIli?=OQGQSUBoC1<bMc_C1GO$gNO$q%kJ?K`@-$JOP0ZCW!!4s&Hd7$m$a8HtMUG>s zo4{!QG&%lu%6ui=-Bro&hGfa-9 z*xbu9`z71l&1?(TlVftpFol%bfAW> zkwvDwNV;sKO1{^uJtSK-UZTo9r5v8o@j_A@WJm=GexVxM)VS`EV)qx7oQH)gqkWPgUUwc5_|=8}#36nm}r6zXFi+U3yitmmZCL*qnWrKd)fdfLCDubSU8ol-vyMK6ttUP`}=6+N`qud*JJ zMITAc^Pf#u)jLDcH>09&BA$V3ht6|xzgUMQ2AjhZz5eX*20cH{VG(%1#w*{RZV>PKd7^yAW+_^}!L{DX{3et5=Ee?0ZD-!1-TA22^+ zZq{tb+N=%c6|N>Xcnx#GSuhrS1w+A%tWCHS7Pk8w<#Rs6;VSM2*Rc+{AJ-G-!%V7+ z-|$ zFf8K&Q^J6}4l_{uNErslz}-my)3vFC8sy3kv6~zgg%_Cvo;h?FHo=+381NID zf_LH5pw7Vk3cdet|6`{6{PbRaR^0cDB|S-*9h0qi{q%)?Mcnr~_x#DjtkgN_Pp)+r zy6u@>h`qwvWlwM(U>|TE(41(l z&B4>b-ysD^U&vg@cF0}Gcc=&Y6vl#$gx!TR;T_>C;T4Dgq9@`w5`zpN=OZ7Yn5fRE zgJ=eNAbKad45Pse#GJ;0us&>O>~QRA>_zNrYz?j}?kFCI?~XrBfDpP9_7gr5MZ~_u zg(LteMw&=^OLmY4lkZa~l%|xKl!sIfwL5h+^*yzQ=An(Gt)+wL?dew;Dn@}(RzfLR z$}D0Em<8r@W?8ACw0-G%7K$Ze^=55mon@7=3G5iVKYK6xCnv;N$f@A6xNEt;c_H3w zeuO`m|4|ST>=xV?GKH;$vxT2UKGANmLflroSAvqXmh6=xqz>s^>3->B8A8UBHI|K+ z9hbe8)8rv}OZjN|e)&^*nF6PaIGiCaC+XpKCIj$J&5) zruMN;qHC_(ttaW5>$e(UhJ<0F;kHp?>}kAc5}1aY?wSqex#r)NjODPEWNmKUY%Q~m zwtcsI>`U!$9R|m7C%{>7u5?zoQm&(JoV&OCz9-<>=!JMK-tj(wue)!jAL5Vr=lfp< z7=c{ibx;!=9XuZ*ggS<f zokFFCrUB{E8AN7w=65!dotV9zQ{^V+1^MFzL1A*Cfi8G}tt$Wk0N5;?ZQBcG+s3zT zKijiy+qP}h4r<$o-MdQJ8rd${16ii5QQkwbNbycNPAMpJRsB>})irgLdY$^2W{_r! zCR@8edqi8Q+ob!ZU!XsrPd6wH|BS$qytj` zEdT&JfJeYDa2SYz803YXLG|z`conRNkHG)nT4WreMJVJ9@(oEv+n_5@3cZ2;Lo2ay zm>$Ehb66}^iI2n8_%8e#UPw$J)({MFg@`BHk<&;exs5zWMpHegDO8wxM8(p>XgiJ2 zm*`BU4Kt5nm=jDkJBpRFPWBZ0j;-dpaErJtTs=R8SMz81WIkEwCs>6;!XL4nxJH!3 zH)6dsK=Mj=q~?a;0Frav-ElJnXwf=NTT7O!Sw65#Aq;+XYmn2D& z1kB7ZGxN;M%*@++Z_nGz%xuieJi{f`jG zeK-B-{pJ0g{YZasplm=nKnzj`YX${_*r19;e4Z$s=$ODJg5qp3TPzm)CNm~0Ci^B6lCP3x2`Gt7 z6;3ryDW?3=3@J<6B{fLH)7jJI)7)vvv}5`epaGS@7~q(p&Xmuz&VVz7EJ;R}v1Q#d zrR-GpK3g#ReYR&7oejz}<^RYV)5E6a`b!s!%J4dFp)SJbxZn zep1qv^-4gAD?b)W7JvnhDp^&kYE!9Hp2gI~vc;A~)uLBTQU9%OP)pUGrIaPcQvDLJ z*P92=hP9pIGTcHqjZ#s z{y-biE>wi7Q8OA@saok?QLo@D9~ce$j&)!l=GUj_zvx-|7CoT1>Ip-Np~z5UXfXf= zd^KscY_(}syy{$y8`F%%#u{UXQEkMHi8b09XHBpcHGMYGO${c%K1FOYs;~f*k)|EZ6n*HJXu zIm`}n_scG8SG*h8eRmc++nt~@wwJ%xum|qNTt%**E|JT(pSk~QUtK+QP#a3~!QE+~ z5TLjg3+_(w;!@m7DehXJ6u06Kq=r)hK|*mT?hgp=7FwXV>zDU_zi;N7_s`AU&g{BBUpz+wueMqk%8n4XDsqp*YOc>jKnymrMu5#OW+c=3)`GHxgz6C@=-C+ z$zUH#7leSem4qj*z<;i1>yG9h?r4US?&I1z5Ut^S_W3lWkDutOZ%I0&IO+jt001Tk zkPQF=tN}Oxbihl11;7oZ@Ne)^0hj=^fCbGlM$#^8>i+fB+fcA$cjC7%q(I==6z<6q zUeMwFS&?e~kI(FF-1cn}2MjZXR{*f2EufRqp4pL065VSaT=Ee^Z^kP!tpGH+$t0TV zoz1LJ=%tz0n9sk)?9V~iq~R8oKO=L$z<$dh1yt%Bx~LVXP2YE#*SerI8bkvJ4-$=y z4Kh;rXXd#qD<;1PVe2QnSJF1QDqdP&^Zl&xn_Ijp^rk`QLeix@O1C#{kDoMOCwFN3 zi#;xTcK=8~79-4=ZkUz(>~b-yO;h-Nmz(dPK{9xovb03Ttc@4cA?j#>1jS4oWveBE z?^+B7x%C|_96UK&e$4c`E_N)5EEs?WIS4lgJqCaM{Jo^^TEHnJ#&D=0&M+uOsVhMz zZKHdV7`4secuarKn1G?m3=F0xG`TwzGsB_cT+NFyhW5y+aM*b))^E!l zyM-?rlldwv_a8bn)%AOHV#zYaUa!;@vR^#h(#xJrbQ!CxtZsrj%^n{e=ytezn&Mjw zoH^{S661RdCTgUNcGz zhkFY64jD{sfhARvZGge}=UXLsJkI@2OEXQuN76)#0N*;;Jq^Li6ZcNzt-pu4!jPg?_dCH{Rym zk{0@)-Qq@>o88h5G;A9C8pdcE#~)-WG!FFweKfCI@z@~twVWjo$L6Pw5C^z867sqo z3utB!W6d&iYau%+ojw%+Dv6{n!P~6GjH&_XpyZ22MwU`Pxnv zB*)v5?l@w9a>Q?N#7%M}oRq~5mBsIt#VwR2+&IOm>`3Ci$H73=XaHCbKmYrl#=BRi zrPSNQ%2Hh9V86Y^9P$2ZT5Ws)Vo3X3bxZHg++Y)GmqXp8)oUYAgr z*Ai2j-I!ASDeMKQ6ty@?AplxzPrDsBBdk;l0Biw{+N-Lm71Au{L(!cN9`CZB>89Cp>J_VHGwNr#h!?RzQ(NvDF*F@hwSUMr>1y ze}W}lOJG`PYLtJ9r*2eWR_gS5&0kCj&tV9`;i{TRuF5LdjKrR6%>-MXD{NY1@lVYZ zZ_6LptjsN)$4BlM5ZhYpw`9*z=F27i!HiAK(-A@vspBz%>Q;eaQHBt&VNlrJ(XbRF z(9}BaNtUVadtnii*Xhsw<{Y!7FT}UPnYG1`iTYzr&qgdhJPY9W0N?@uexD{*;8hFo z7Vo4UsPru{NCLmI#&5r;ysl;*Z_MI{&-OynEB^!OfU~W6jhyIQWA~NNtF!IJ6sxcY z<^PeNCzP2Ph6d9JVWEb4U!U_cBEqD^M$9gZw7(6>=YofK|L<8Qkuw?Oc#ttE#{nr& zmC0;-vHH8>0`SOL)v}ljAwEw99R{cadLy5k)Z5R;8@`=!ovU|POtuKV zpcC`inv2ta{V#qJ{>zN4{84zg9BK!@yUoL0Zy(3i7um0{Wf^VIn7-O>kf-TQ3f6j^ z;K!>EaaB0)(m>1>B$|V6u%lJ_*h(Ccz$~K~5xCz4akBOpFVyXTzR)u4{n~mbigCak zvt7a8LR<$Icc##SG&oI{Sj1>sG@t*PE?o`(uLyon(=Qp#5q`b$URfin%A~<@Ia=!# z{Lfs&>(vNF)#L&(U*uAhhB0*chwsixq^eF~TfjMTIY!5-{r>8F$4c(y3lk*+O>+f3 zbu$$sZA*DwHB)6nEsMx!0dlA<22h*0&ch1}|2a%Z3$!RoT}`~=3|(!kOaomlq6UPn z4n~sDgeE~%{e(77fzN~%N!!`PI3SWxUH4FqG@f4bX92WzI*oNS$|by%d@R`Q<7&>V(OS@2Mt7XM?R)YQ4W%Q=tQ8m9ILXB z#4d^-@XpfzdJn}4!q1u8G0yR$YJxr6MwTVix3z@|5`L!WKL=94Ca4M6gib0V>LuWK z0zt9S^ZhlYOMrlki5bmiZdNzPV!SJJeOk|2t8n9ba6h68!d zYW-5s;^0N9glLV(!Z3sNfxuBxwvmj=M$A-#AeNWer08YfGb}`2H+r`uZc;=S6;a`f zwltz=g`l`nP5h8OIS~`N`GwcWP-Yi!VDbqAL2O{{2#(suywIx7Eo&->2A9=%!IN*kbazL~ zOh7A%Lv^o{8%82 ziX+fS#E)2;*Nxs%2C_&2Cg7$LCE;V(PU`#{cc`yxa9H&k%r971bMkTwKauCV%RUJ4 zn#u@;LJtWRB#^xC2#L4}1zvs<#$@|nV(%W3)@LadtnFpb$@Q?+{NUsZjtN^285XpFZnndCu~ zLza819`RkrV){?gAo8V(GGQTAtfn?8sb|lU^*D{V!1oAlJy%0>{KIC8jZ4VTi4&){ zaOH2Ma;NqIs?m^CuC%(o(6b*|d8SXrOm#jq?{5hTv1c8N?0)-|DoSITtb(!eGCyoE zYrVp+Isu`6*qtpDzsVt_s`LHewC_fNKFa-2Ga_%Z+#yC~B9XsIyjLblmj*a|Ya;DV zC}T7`5MQ~@vD6Ot#5ttRB>CQFup?;v_4O%Ls5O8Pjf5J_ZVguqTRU8Tjqr*{6Toma zyWz?+)ucX}mS@&OnNB4KFh@7;6!ySaGDBDzR#cs-u;VK{eBkzNSvGPxaV^g+h;ar= zD^9NfNdLG3cGQ$)==NGo#Ead#Y0R@HXUJVOUuNZ$67K+cqV#Jisbv%&ME)u8%C|Xya{6Yez_c z4ih+3NOr!k-8QXz-zKsGdP^ocy!b+2Ru-v?vsUwL9M$(p^1eHwKh@!>%YG?yeBh6L z^CLfxIik^{VyK6{9*p`V;}kELHbBCj^xxp`f|n4owAFV|Y6HEB63L z!B8sq-!|g536XVzNAl(mv3UCwb2>jlfBs>w(W%LgGylz_bME{F^htf@^O0^X-03=j zDR;Quq_1}16(prc+_p3}bj+?)>H^j4q%_J^wi`0yS)89szD>VMm}9?b-U8W#@_F~+G22#9Qa;$ryfD3#(bB$f4Myu(A!7A;$cLG2Ia5}5-Iw5JJQIO7-qwfqEprEVs8l++S zdZLYI_3LAf^ldP_qRO$EX_`cetvz`c7~f6w(NrS&*JM~IvoBB83hE!Z~GxdUXo1uRM=?x&|3}Rn8}zjgVmck zA17wenISJ-yobjt;)`KioWASza`URKl|x&1JuynV$B-|VeD>=vbMCvCoaw={hfcQA z(BTT=-o2N55=>f?JLspVe6$=EP}0%W0)k#vyy;Zy6%R&vk!Afw#W!+T77 zEP0G`%Rc26HB=+`LRu{#@JQoNlBhWna#dS%V)u`hM>Zw@Z8~E32)Jec&$8@} z{~J*KZ@}Td0iQYt{-FR5dwgtX^e>&WsGNCo5SN?2CqWJ-*z+YG+vEH$5ru>Wia}Rf zfo*;8K&aKuU#|P+OChFb=$q#*^s_4~v)^bGZl0!Cs;SY`#ASU-%{4{`xbEK<{~ecc zy5hmaVav>HXSJnGj7=PEA4QZn#7mo#Ngxv2!o?BbzD97i(g_4TfpsYbMXJ~G5wK^WS&>9{*oq31A1bu;7HcfEfV9TS0I@CLtn1K!r_+ zgx1hpzl zQhj|_-|{JM@f7O?WEf<+iyc&y(OJ#X*%6l#-RZJ844WwSXGwX6(HI+0t5~_DrWF11 zLJ@CCnWBigwGmv)f$S7e|)i7pBD{4|mk~{i3ax zYII4~OUt%Hj`U2JZCn1HR!9YjA^rYX+Ydwp3#>nvyC{Mt_c6}2H2_267ts_&|NZ(| z11?umN<5sV@WSW?QLLpg2#WKs$<_l!g$iBOj58!=wlpQCw8VscGOcpSc`fL59hklk zziMSnHd0=z7AmzGaj0DLZ&>)j=R0ls_^3P6=S0U*A(DzZ?0yWW$Jqf((8&=?< zTSAzw(QaTgz_!L<719C$vjqxdAQD9=S|?edf5F!(b_xbeuY5hNNR8x|7H^K)H#>*78p$e`W)iAC#U6CC=whVPq*YaaSK$s_uV)>&d#?zP_s1qAFF1R+0fG z(TG4o>Lb~1t!n}NJX=Q-=s)D%BN-!TT;dbJFieXs2c86UIFo}1)?!tZM|I=1Fq z&c@^65rYFj@>n*>z1sT(#(P6n<`QMesK-$MN~HH|gg(I=lUxAPbf`9WG7Mpk>CjYR zo?c%o>wH}@i2eAi-_r;{LNWo61qetpaKr@r)e2>C?N+*`^=_9+Y&hlV-WhNr|Hcg! z6tc=O&~3@(2@5yc`a5scuUo#0-Y^mg074~7?OY5=UMsSyzl8HAfCGgMMg`+DMqk0PonGYT16 zI{!>>xE~B~am0=rNm%?47MJ!GUcedI(uoOc#f&zp^s>P0-u53<1OuX8x9z!ex0?!4 z6%r=YC;|I0%3i|9J|H1-c2Iko+$7yyhXTCEDD{c=b1e5j>C<8ePl76yR4r?&J!rrblz4{}h#t7>y zdeh7h%+Z&MvW=@+$Ft$t4VYV&s=DZ7O}#;DkYp2P3rq&>X*)Bm_d}aO_Yo^N#&)9J z3qPSnfmpr2=JY4O9zrSH&=3%0nE&qXt>VsxRapm=*gw{tG}_Noh*cj=Ly712x5R4i zRo5Q{aPx)?$MP3)F>W#LahO(8@rN*E=h*h3*XyNHuK=JPDqq0An9@IyR;iU#p^!qM zRiPXR)IXk2bb`0}`j)tBsA1(6Q|j^AaZETc5qRaYwLG?wdt>iOxa_^@CeP$eo{-M` z(Qfwo*NC?(V}vTWeZA(FCe@i$_QLYV&1}!_Y;!~j`URwZ5s|CLWsjtTf-8;w7Pmyj zBrF3Aw7*`Ut$q)k%6=YEP??dBmpk> z_or9y=7&2eS00*Y*#MqH0MX}evC8Vxm3dpmIMh%Haz8o)@CdI@p4FBUA3CErU!*L0 zc1=aD0EsJ&J7@6f1n}%Nc!)|zK?06&1q4NaYoYqSwR23a-ua|3M&#K$XZASt4--U5 zlH5m}RodK`Hr>>Q*ppYab+!6(>(0#Aoo`c`eHY$I|Vsfhg-g)b*8-R5S z1V|;4(c%;?Q9&7|%?cipZe*>?Osuvqz4!gC@M)^G9De%!)C~lbp0|wzsmuqfG@dSg zxAyevwUfPv7u4h8 zP>}Z`Nb3Sxg3gx^kZ-*8`kE>Lc#&W4<2#u!-sILQMId~1i`Rw|_09%7Ch!oj~YkqdUTRC-Q~vmW?9iIW_M%^3gwtM#l= zB=wg1S$q9ai8ZOTbyHb_6*9_7B;Ed!(5tE1`9o<&FANM@vUGlZHiQL0SK^a1c zH^BjKX+&ntHCpjP-G;A4e6ZO;V0|J>i8p+R_lGb9hm?-VfD3rCdDo~Fp`lvL9%iNu z+hzW*w}bpkDNEJzAflu#Vaps|yR1r&LXIG!5#|fuGKZJ38mQz|W6fCA?E|`*?aNW? ztcwc&c?lX38Iy|Yo`mlu3HmELm)U(cU5M6CSHWje=OpjUVv8F!@uo(*MeZz159l1! zzP#LdM4-3M*LxplQ}ZUuq-yBv!ouJ}cMjJvWG&okIjjlUmu3n!n)&^z7z98U$Y05Q z|KR3{R~LRQgHWcQ36WI@oApHZbYRff;*^fZ{6T8Pv#izqu{}C=WLnTYOKN4wG3YuB z4`))bUDDCYMVLHa!$a>)nHH{7t)RJb(SXFcyMy04%mM7J$Y73!gRaHw`GOe0b)pK64tmYM!Wx2F<)AC%` zY>Q`X*|g+&M>qFWj&QGOk#Vg$Cu*;8m2oXgFJf7@WXLnETdOkdYpu2X*Dla9?mAPo z&r8)bE^^d9c4)|;1O~2uz9Up-qj1%MHi{VPd24_g&=U?{J41uNSu`8$z-XwodD{S1 z2r{!r8IM_GNc%i}Ky9m37Fj_(>XZea`FKtAt3q$PvKhV=kfmr_3RbjX#!}sZn^2kT zw6e2yvOQS)^pBSAzH`Ub+K3fzto0YU<^zh|%Y`S-bNtYCgay59znwQd^P9Mx?w_cNaO>%$$=0Npr|GZ!-{Dj z{WE3jNn=ILx(M*0M^2)jg(s4rj)^L8swK)J>tetaQ2d#WmPHikVils90J%(VFgFBA zKvT!fXeOK_%P~biIO5~m%rii`f&Cx}i%6#OSeWbUp&9r|J{+X-)<-(_oxLX|;KB*p zfb@Oww#n-Q1+$!gavgC^q(^uDE?+Z3msNakCoWqB5hr?T?1wpAWE>^KWjf78x)m?+ z>yHgpr0jOmg%#&FW~UEU>8b0Xe#PrH8Jr-W_>My*B;$iKFjQ7gzab-e+Ph3AJ6lCN z0n+}3lLn1*atZ*yCzYwQY-{w3R)BNjiQECiM*hOY(;vtCpwG0D=7~}TtQ^1Yr5M~u zM;R_LT54eO>iGn8aJjz%q;3g>p3MJV+M+9z>Kle{et$R#$WFo_1*ZIXQISNIor0yi z8zWd&m28pK&{<>_tp)JS0h8YCX;;1L{6?tVpFyp`s;=pKX&MP5n7v_8PXxm;3PY4B zXqFNvX}1i&2Us4iApQUYfGSt_hXOXu2QS2S58xbCRM&!FAdGje*6^-rcX#ByDy^npe!BR|I-4Qx1}bm+$ukg=kUcNW00 z&RyXE50523_V^q)GldpBMDRz<0>c^?2!PT>2;&&;qdpp3Z&0H@<6xCkyIVcKhN>2& z6~$fv%k<@X_;uhb21Jbc;AYx|temRc8Nm)cNszcc0fA%u&ocnGOOyn4VOWtU9d9U9r<7wGo(a zk?k3td0xbDR$6ehvK)jN*<>U0fyx-G{g{uYj;Rapn0c&O#`@+^nlW;jUAb;#^ zW?$aOX>8|(1eLVbGT73}aiXm0aPMM{&_tKM;H>#RpSq$xr@o|S*C>!FhU%?OVx`8q zW6z)*1Tv{M-A9%)J}8J5e;eQsg^n8>eAlGQ_9xrW8g~n)k8sAT`7Z4+=$@*AH<2wh z$F!0W2>!)2P5JIaZ5#&t!iXd-b2Q`hTH`RuRrF)BHG-7xQeVY=>{WN5HVOHws?6pe;9**t#31dp{OjhWgzZY6!d%?9~Qc`v!B7kG{35rK6V2Qa>4womql#0Whi}+jTj?U>IXsurq2J|y(U zP{c)8K~&6$=LJyIaV^Jmv`&po>Wizbq^@ zHP~!H%y;D20ymB}KTNjFn9yP80k1n${&T09X{x>vh2sJ%xZh_$P;LX9O*Gt4;QkYK z9)FoX9@9w#uZ5B?(t#;79L*VZTFz1Cann6E@{~C5u#qy#Pejmcwi7x-#zYnfLV_|8 zidr_35F#!hVr3#qS$;gOELbKLgt1XwKyi?>=x+33&xy}p|GXqEKjZ9&% zj}WggfFTD8gd|liBs|tXJUEI8HPTta2Yb4IjP*Ssh;20#TQn-GWouR4wtW!gH}-q? zq)O|-E`@TI%#c_uAT6bYxgq6=94~N$k}BjO>?R0|z0HFffmKVCBeq(WSRVc-PLOd` zB`SpW1sT>cy@@qK>oDS3O8?W8Ajr})bkBq(+I&+{f0z4%QX(W0g<7#vrUNRaQl(0< zO0EYiCX>Z_fos$6yxETT69$8csoK$av{JB!>jjI&YOz|hitUEW<+Eane#h(iaw(1* z3>9m%+%c(ihAmeII&~J3(8IqU*rWEaO85vFL95BG$VScef|;TaE1J!|VDN<6WeRsh zYUgd? zIuUq`;Z42F#HfPJeAftF?(qWu1Wkb-$vU3~sKy-gn^>E9$P&$)v20>}#v>8oU|H`! zrtqOZ>CMWk!;?6tv~CBUTtCzn#nPaRsw|X?ChwBTG^(A`iMm^+`7qz&%2OE(0Q1Jg zb*GYw_0TbwZ>)XEcKb-eZNJ-h-u~X}-w>p>ALlzqIc4m5Wg0gza^TB1u4gsPh~`PQtt)@fbzQX;EB;oy zLL`!)LP2*)R5ct9OUIYPzyLvk{l}M}u)x#~mJ10CRTUWPEfxoj`pv znCJExk6q(3qS`a{xPSpBr{O@*nBlt@V6sgsViz?|V`wEDAUld%L%B%%#EfTRot+u! z)$urWhr|+5EIrUB7qKM}|18G-3F5e;YAZR#sI0 z)6WA408u?$##KJdk>-OX`*~-20AxSbE%qDjBeV{ZOEob>Et$?30aon=fo2gJJXl#~El}#0j+Lv^g)G^5P zf<{x1S+wGIQ%f`Urb-wfC@|Sj|56SM3{5uMwfl0rWR+}>Rvr3^?1(LCjXzTbNC!Cf zKmt@)<^hw3)n9_hOA-7aV?`V3q*M=v_ygV|j5!v#V}w|a(_rOUj|DRxLYsv|qh!=8RBjG-bo|K_ak;hn1QJm#Y!&PE|0addHPe8`W{F3$kxy6M zm5=~`%T<*34gaCf5ov(5mnlNZXdnk|XBIR98^J*7adtNYVNpRYl?p}sP5*_D*RH0s zW(Ck8-G7C!_7=J}t7eLm!)+tLDl^z~KDQZ61@u}Tr|j(0kftwBw*H+KjF3YoVM#7> z(qiAKSbEl{Wyv5i+D#Xq7;G8+5nLVtbd^-M_|drNs^Th9yR@#Bo@ww5R#f= ziA^P19?kJYJrzE-;0v&`H9}QLNKsqbGahbCCGSBwz%nNd!5v z*^W4CsTcJthzr-rG-gbG$Ol-*JqV5XLDi%*-$n#n(2r3I`cg~)A_?*}qIM}ANRqjJ zoXi|llvGtbc4~y>ybfbS-Q3~i`E1+fS|SA*~B@O8tK8cPM4AZxgP7yj_WrV#gGSbW;c&S z@)JJIlI(gue@;Itx~Mso&lins(t%Fv1Xoqey>To-h?1g$%SngsIlq+H@a#lXXd?_)O6HB-al6Mmoe4#PkL{j+%Tu&0#b@pYUlJIq4XyFQiXBrNGny2 zf!M@W$({rc;@3}tM9nxx>(O4eD547nE)s7vbq&?BDTKsO6Bf0knw+4b1sidT!RwGU>jY&lHDuj{xxx-<^y^;yk>nul5qXdn3DfT1{7sY3kBZoyb z;&PZ`;Pt4A#N+_k&IFk_l$wf?>v6lzvY`A#>YRdGG-{N|60V0-G)I*aD}xOPBwj<~ zXjrhr=YN(@xa`~e+u{jj%ZlN3rj4u)i&Wz}tuNFqh^20%ehyR5>dbu2z%L!yH6%hs zV#SiM2=SDLPKHNrKD^am}+}~50JjD5M zg;=*|Y#RljiTvRY1?Jcb53}wrJ}g0`cVvz9Es7YZ1fSO-E?6g&;B;)PVX;&U)A|?#lfGecZPrZ^to%PwgLJU5vKU^F3VF&=LaIgUc;hVPjyI>4M3mood^P(?KiG{EJ+&+{ikg{Xf_WPzD4@ zi6V3}F9Z&Z42>>B=R8da#ZKa{SK%Pm;Rsu=ObHN+Kr`N|M0LDCJ9ZHS~dt|(L+g%661y$LqDUb}@z<^avaFUv{zO zF{ah%M9|!LwdY*1uP67n&kD)e=XK}tuJV_!@}C8f^xJj@PbVBYvV}bj7`oH;>Qvd9hi5abq<|*i2=b36S+w|)kzyJ+h z*NuzzXT~MygQi{HPs$vA(rg|Id5!J^hr4lZc79P4A@x7m6{!)OIWKxAT3m>u1ziES z{(jBwRRK$RXvEwZ6~1h6voDsKw|*wUQ#<-zmd&++)cY@f2{=W}G)yv#1!S-wgQA@A z<1s2&#L9ftoJ-r1-n0vo8?zqLU`3BVmOm~B^FPl^j3dl}G}9olIH8i{A;+wksGTr& zK*_vfjvIm4OL@5gXs6qf9m_i*RDjBGQ)u;vkqKm7aNS`@2p6KADOA8O8l17i%0f>9 z38~UABXpYVK-h|R*Fo)S*gG+;eY${}Vr`(&Nkg5TyS z#2=03T#HBor7=;t2FXNNw40ygs)R^*%;|+;co-y*V0`$W{*4fU1jxw9|9XhPG6a|c zCrm+=*1Q71cHezhn*YFt#7qcvKhNuEHw--n2ijoFFcDDs^X!j3|#{Iep3-Y#E_^M`2v$R@hocUiE{uPt2udDMZG9MwJ%mPJ2P+)MN`nPYKXQ+4R{p5Tz`;H1@ zV@6;)hQqbdtMlJOGdpB1>eK^1;)CR_nH2;!c>mK1_k*J){&-|&GplCGy@7dp-MaP% zza~oP-~9=Gp1DP4fc3X}p`XGjq`!AjZ%*>|%ubQY)R$Wg+mdn$rN#MynW+=On0+^! z*q$EuzK#^U4weZ1kOEpt0fU2di&oVf4@e|bz(M|j0m=dX!GWOxsvIp85*nx~Ff^IX z_ZS#SVoS}gDY<9=3pwvsg0L65qHHgwas>j+Mk7l8ygxY|mdchL+b;}f;+mH=kV+=3 zGVjVfw4&9cDBf(LJdAXqk4wMB0D8sL-2^A<% zpg@Jxo+k|k5Y+4l)83>|thbn`aIz6;`DR_jQ*ZeT5WFE`z<>n}7%-%B>MKTfa-;YI z&-3dM0K~P6!^W%L4yA3uH{CY9yPbA^wOOIxm071giHG6rN16~BwUZxtX5yAkTRNr? z9kV0)h}oLv+Be7Iw;0@%W6Z;BHkFs_iuoX6w6sS7I({ zfPcrWLr$5JA-la)&+@@TPx>1F@DWez(a*dclD!$a7>PVl*Qd{U7*;Odc`qnA?do3* zB}cn$E96!eSrY_nkRm&$|MtGPin94UR5_BRw8zina6&l%B^pd9lhW@Ii<7~UMf~h~ z`#99Z>%zNxcx@;it+RdYVXa@-$^k`_$_<}$x>W0Q)XKMj>Rq|HX^l?T%)RL`dZ2oH zhm{1>TkazOUj2yo`o^K9!*Kd_Yh&du^i7&2?+NDTqrGX83J=|c@>0HznuCLf9j#?i zrTI3m`m;((%+4b!=d%Xvwth71cB3m&s}8JYc?y$a{ecKdYv;j01|3qisWM#VEFRtT z&1lZ*Y+w>if8(`L`Rtf`zn*JUqB`+=)3`+T8YHpRefB5iTA_305#8lwRkLfZ^J(ky z>z5-zg}`IS6U#yWtq9VNqNsjwaL+zS^ z;)AYl?&M%kB~nc0J%5Y$Qc|A!O7lcjW#dWjxl!Hs%A3Ek)@euJbc`! ze7zUY4#po$JTi+sxX#&><9yQ(R--E6qCDj89-Afc5|bFxlV&7eQEZTM$WN@=XeF zffzvM)Z_>f86sOIOyzxz!E`WdE=@KFn}l`3M)6Y)N}Y}Z2l11D;i&E+3!jOHqW-+> zBa|HxC9n%ShB&^Ysu9X$i3$+ibZ-C8=;Ap+UqE|=WkrRt3XC!%w8=G;`vjYO>J=MHVwF(MwHj>A- zUrLXkh;-=Off+~0Lets;tvKFg?K3z6mekR}bn=ZvKUUP_KufannZk~I*0@vQ+7N(( z5djJi2-8v}!(uWOhUH*rW!8j29oc4^lH``n6R8_*wS$8z03k%gD+Hy4gef%B6QYAc ztUmHvVUd4QK@%>R4>cnJQf-o|M^DS?30$sql?c7`hD|*9%vFAT6zXF55d0I54}!W3 z#wz_Rd5DSVJ6VX8q-*J9C1hthUZwg-J=LRCl<$Pn3NjVynVSAM(jq7mVw8bsmZZT3 z-6Tq*9rAIH7=DAK;v)$I=5Q(i4KcOXza7dt&UH1fX-`~Z+;0O!oF%jgW9Alzm4&?Z zUHfWwn(B?0^#zmBKQW?TkTz=0+TJqLQK{;({TxF zBzX(WE_7?!_N3LByMxn?y)A8P&UcvBDZ*O#MhN^8rBk8JK!{g}{u23f!Ji>KG}w@Z zD4i57BBcTII(lf|L{? zO32b35Idwv1&~}w5gdmv5lk^C$5YTM98HKX{QNQ@+kST-1D?a5N0|cIK$eVPN)wq7 z^B1I*ovT zp1oVWvG#%u6ZY!vVS@PdvAh8KZG5AOGt8;~-5iH9XX5$#;kT%h6R62>It#P*n~bBs zEc@H}J2qau(ITirkK<3>fugj%*cyROzJTK2Pvq+FzD`ne16(7z)I7S@T^XFpG9Z*i zR2oic6xj~#g&0{th=yP!5DrKP7L38rq=b*4Td(lEXsw7jLerF*ta{yOt;zY;kpi6T zt5Gni2J9v~fC7T3fe--tKvvy}mk-bOXdAToIhg{zoxbUkDQ7R&Pzlm-0BvNmCE^nY zbN4GEfbPwIHB5NDabTQ{w2BKQ)M3k$4C>ghT$JE?MCtA1gqg2x3>c`(6Q3@UKb{z1 zmKG?fyXt$dxvzJ-uW$lOcz31`bcmV)X832ZF&BNA0=H+qnVh_^?*alDW_ZFtX5mE| zkNgu@Moz}S(a7C^LHqH^J}`v9aJQ@>4UPjlRP#)EMXH_pa^>51MvH*4E&&s7xLszd zxnqOFwDp*PmeC+e8aS$`E4X?D6~?j@I8kvktKeJCA^!@@?#>`|=s5^%+@LJmG&FGe z_+Lwq-DjZG1l7BXERA7+)x4VG8u3blT@7*8M?(z|AW4)kVG0o{S+sEB3K}qJ)UaU- z8#>uddWG}p6(B&_eR_p6df;{9rcsw53_(%)PnY^i?GUiVsceQITW?ftOvG~_0 zSThTIOv*MNd%;Iue-OkR6U{so)m)d{z8U168pX2he}Wu(hu~MNmMhot6_dv!$aa zO@LW=B)-v`S!CyfwfAEfW6F()HeuO$VgRxlFaV{}s(w_(q-yK2BIx^+@gs{G*w7|c z89*0C{p-C)#R?#87)>~N5+sA`hGmla3rV$#{)_*YT=i4$w+kzYoVRoB*N^r(`{VLQ z@b)JJpvg4f(7`3$01DTA`(sU+%koFQ&MIOmAg?1xt6ouI9>~YFs&@eY9og@|{`Y;& z?`KT89$~{mgxUKrBMDMQgeWN`QN@h&5PLg)rlBIU(=vTPlNJOlNOG{Ap@odKM3dIi zbni_XdvkNvt!@;ndZ+U?19q#*+gQ8JTwL8j5TQNl-Ya4;D|z7Fx!LayM{J(}5Fi^! z4%|G5(0~F1cr<|0fV~}?hkBmmUI2k|JQXb~H8(X!ExT0m4N(Y^5wf9_ytJ$sy_k8? z_2RVpivLeIOu${V!5%;={d^Wx@^+V#{)#2LZ3YJil4PSK9VKbvxzP)V6;N)QCRKF* z5g5P}qnCR(uyARc6SQj`?;*f3=1RQPCQW)wld)Zv`gGIN(Z|f+F`${22Z0NuTyFV? zr>-;p&M4rNqIbUBGjMv2fw6tPtFjljDY!dM|NdR|i%f1@Xn-U0gIIOKSU!R?;Bihs zCpG_UOoA=|PDBE7d}IN)A4f+F-u~BBcY)nMCclEK-;q>RPE1Ndq zLL$vzbrs8>qrww@0r)?_{ygTh+Om>C9OCfM?gWcl9w>;%Rbr$`#CkPv1AYc32TAw_ zDLQZ z>p!64M!wnh`XS0Xt3PUkAezx$Z6IX4g*eAP>Fg7wIn0{p0Z{nu5>6z;z&}KUtDiJ=Qnm_HS-5H%Ty4bP+YWnIG;Z-bERif6vwC}fkV`<~s@>dF671eJ=dA^IE zwqh-7%I(d=?UB^6CbN<6utWlFfyFDQtBN$Hj6C)NP2tHgs+YYAv79EFTYMbPJDfa0 z;_I+IYYQ5;_ag8veGL=A-3IrMP}?sOL+Rob7WHK1Rr#fnGTIT+M zdc>cALEBrf3bcs`s0%lR8;_D#S#3`&;y7d;Q6T!Xyzk*I)0B7>!% zk}5T8JRFipB-21jM5AI{~J0gj2&~gklCf#HZtSv&M>Nlz-qqpgjwNxkr&bkwSpq61HWyG?S zcuMmT5Pndl7Fj*mc~*_NBB}Sp<>oi8diW zSwLFi>2f(6{E$jZ$sY43Tuz_-uD6`7L6GR&6a$qcytl<{`iRuzY1!|d^w6rU#qnv; z$MTevE=o@uwO}J!B@@IDp(0oG9`8xWCfm=p<*P|&IJlxWUsA>oPE(Ga`-d+8RK=cs z^#n>l3%%Hp&~)q=HTbUtKJf+Gh7diSvQnk4<=0}rME4wiLzXpO9np(O#(3!Qm)Wk} zjII{mSnag*IQ#@Suf~cnR}H4Zd!H9%4N_~6te68$hv51}gIHlEszqci6vGX0Nj$*> z+mOeC8;~}q1JB*u4ayYf9-Ln}G z3cc;4m1{YsKC6d3IEU)Ky4A}}B88xa?~pES{?WF%9@Dk}=AI32@+;Hb%5vr4_qe04 zspxmXE1!M(Yk;1Q7!d415esuJ;V=+Z5Q0_K zs}o3NX*!56tUE^IubBmo%yE&R@*>lwVo-eBMqaL=`VzhVy=VpzDmTufgbmpny7cm) zkJ`L|6zKv4dci9L78jo+KCxkZeCX)(0@C4$)ZzW89})IbmJcnTelJ8|51+I^Z1PBv z!7GLqm$ZUx@BEJbpyz}X14T%f0w8q4TVi-X?!(*jqn$;C zILluiE*X=mB@bX({KFYp)w`-fGFuJitbvoELg?Y5-9iG`l%7fbVP+w{T7lc1>q~_8 z3Bu|3At)-<4^-*5U?n-Df*$H*cObubcc!_Y5;VBfOiUJ%M`&S5sx!16&D4$C>TBtM zB#R1Pvd={r!_CA7eYL9?@0j?qsAwve{?axZneMn+Y?{puu~1EiM)R~dRH_tT3DWz) z)R03pnxgoQj_jz(R!jRk!>3_I*0fS5Bjn8Se>X~ij&4Uvh`ZUc?sS&vNU;gcWD4jO zTfxp#%ob{;P+7|yFj-@jySqAM>b9FujuX5tWwEoJbT1t8IT2nSQXzR^IoczSQldj; z7JTd)z3yXPmaytqHsIX<;UKfLFr!{eEGmfA+-i^xSBes8LBda8NyOD3Qn0!Jz&~oN*?I5sGP~U7giG zWC2K?*b_D5U7a|d`f0@YmrlpV!nr<`Q%Q5Ko{uGT_}`VBTYLf=JA80+S!$&~furwb zNHI^2y*bbypXz&{d%r}r-rfMSPKf@*^1$yOXJlGOdAt*d<;l?dD?o7x_=Z?W-f{|a zH>CUB`li8JD#F1+Iv^g=lZhbG(GMv=@sCr~RE&lQY($_D4N9Wu>Gd_@21fR9Fd#(q zHRfSOKqDT@^YNK=YA%2f+?C9VZpY8CAP5o&{WardJegRhCC4m82g-`6M|ea1=_+L|uDJrt8e?T2HKkNLV8Qd5_PY6{Ocjfg7;T7&AO(~gDN(i;E>jNhV_r)-kcr)&}a z0%UIr+Qj`_YNH92BPZ%Opl*Jr%@gy&* zrv38(Tdj{!JX{0}@(pHokkiqxLNAmCEfP^++YIO~e~_1w0W8v~Hw-TaYrM&$;`OO3 zOm=i6MbM^qtw*-kRU}*yFRKb-h~BG7xwOA%=sPv(P6flaebzL)Ob*Z3YG>!L^rnoo zxwR~6;#_$C>db26iWOR6qRFR1rq;VLA$UEA9KzqB&nSiM-$Y16R9wWGz)nKa#w5G+ zfM{9RmsJ#xY2V!$jpfh%<{sYMA>&bG3L!UHv=4i(#VlQxFQCZE9ub$d_yUwzzNjf7 z;S?ZA@`fHfKDywK+4f1yHMR~0T0$)^@!WVz4iVJH0^MvZEmd$bnwztuZ!yK9gQeD| ziJ6TZ_+$J`D!O9o-L*;+C~cJI^BlnFII{aLdDu>OOHpO0nPX&2-nVdUBve1v@0zJ4 zltrUZRy99)1iA+jNRn~4_=?rYwWy30xq1&+*(90N$%A}eE{U;PUuZWx*c>a$rEx?* zT_8XsOXU%hJErzv&4m$=2At8hmS~^i&P&rghYH=wi070fGYRG7%uwb5Cg-#2eLQk< zlQ9zGG>L>#W;S9W?|@?v<`G2;fDdAJWa1HW8#qs20}Q|{`U>d{BP3MKOwsSv^G!$z zDG7oMXENlpHIKHrN@{LQ#9FxM<>b2gy*N%?zRd5rJ5MJI>Gi$Sb7nvQdM9FM zeoy@D#>u(WlIp1pK0K?xmu}fOY)Y|RmL_P`2||*hT2*Kh&);MtzHC4k*A&Z*H|;UI z>`^`znuDjZV8TMS#vSP-+#d@8Nk{i^Vpj>On%feY@O9}f#D;+D>ERdcE)%R3p>liQ zO)w*nAQTLZd-2X2zR2%ZK9i<8LlOr-(S~T$s4S%g^9$JVZQm?W>pytaOB!nM&T$+sG$%zxaee>=cd4hUSf7 zY2m}(P>;BU_D`7Be=Id-ggl?8^jNS4Cwvo6?ay`8+wRbG*eX^Z>@Sd>TqG5I1#lOd z+87Xw03nhu56pLQQfw~g9W@Z4p=~r{fM$zNOrUrkVICb+6AB63Dvm_ESeT-{MOE|W zw!cmsl^T%RVeI0{H}piUJXw@>ejNrZg05828lTom=*#6jN*2I*2@cnSv3Leo>uRRu zjIyDA?chZEEVbl=eHI!KKq@Qy=o{Qe*k9N907YaZQVbMan12;5 z)ZefMj1Ec(Y2PVibRIx55KOQ$!p(AhQBAk-XQ$=Pdt&fi; zjNp?Y07eE?l1ySiQDnR^YKiQLe?XP^QAMDt{7X^RXLcb^yMyi72=4_NK!)VD04(L8 zzSe&m9;>HXiYv3*%5dG7{G3F~+Py7JK&de!uDrX9?3N*VgPWf=k5z-Ppy{f2rpiY? zaOnzPGhAbQGwTqoSnxV(%*0PiJQ5sa2lj>V_;{6PCDP`k{TEqQr=}T=_L`?OZf) zzEXGV-Z?roUiwg=ocrJ9hn+zU^2$l-C2B}Q;6##SxE;4P%hp(=;AFW^g#-NzT|}Ra zTD|3vLa3IkR!+aziTgVUN~r$E0pvNQ{SUvgyn(;co{lBqF|LBJ0P)-3Tt*m#jz)8O ztq+r;;%_s#Ii+a70_f~~eBK*qHGtYVIrJlGGgmiwvWbYPtN1j$)eiSH`Gv1vtLH%- zmwr$#M=avi0e2A$qY2MCRN^zC>+>qLSK{lRRyos&^a44C>kp5Sui$sq$2BJf&MY-{ zvN7UgS#b=?mPz>Ae^3j$e}q$WyR_tfqQ#mlFGE_`z%jN}mD>Ki&c0|j@Oq3sBsp}U zAhinIqkcoCLl$b$yP9G}QwVJoz`{;)#t}AuD%Sx+hnf;p>dtuSu3eDc#9p-eGSaaN zl?s(bc8a|pB4rw1s({xWTSbel*S@0DW;%Lrdz@Q$2o*yaXbGf|5YU$L>IGIssQ=)p=-X_O+V2^JnhY#2q^i z^F)>%woAX7xrmYxiseYa8%66x&7dbk@*`hTJxdYeV3@2E$_nB5|Hi>Dkn@80hF9NL zpv&Bj@k~Js(svC}!aF4g$A%p!_(I~2p>&{N;HZMT_6!|%EsLt*sj2=S05(9$zsQR- z`0e1g^1OR_(X;CXr&B&?&v-@upAQ>@ll~H^!Fv1*^)9t z;z6{q1*{f%l`T-;i}pDveduxFdAj1Mf6D)kIjJ2wc(tJ`DJA8QAsLfV?SV-R_MDQp z^Sw%Rmm}RXz6>0*PE(_%JDt$<_G&^tmbC1d7nD%*HB{%rRy-sK(RB6N$6cPQipK*7mp=1ZzdU>_8vk1ptqWuw5x?t&Wo?&N%ye6v? z$dN0`qB3W1g836NUys-`-!nLKat?*aO=rF50=N1IU4!z$XgXba z^*FhEvAj9Zjkzr&-*fFLVox55$V%UGA(S7-$058{_^pupj1gualw7;D$C<D$0TGFv8XkUtZFrg$XQD#dxUBt*FKancxX?~>12wAw;*q&ZhIQQ zfgCMeH9{_G$^HqSeF@!mFQ`RZQK2Ae#M`RYcvlZk^u{XQE@~;Rr?ghyVo%=3j{J%3 z@R>Sq)}WvHS?lmkemVmt@Duo((jR;n*^UZ9E!(PsDiX%1gPC+EP(_2F1Twu)W<#Bi zy=1s!Bx69v6buHuskpLl!n1f_LnZ}PbIkR=%$X^xrxNz+-wmY_SHtoDyKi4Kl)71b zHOI`3ER4*VP`gVNhaW2d0G_znxr**p>=y4X>OvvYYW>3dGIHkRrjDQIn&|fvVOp|p zsYQpF{$8$(wLH1nBWDqmvmn^QeHgZaNk83Atfz9IAdD{@`4Za_O71-RhQY=Id*3|H+cj*&=usM-7$z!mpySYE7vn6e zbb%3nW5RPXT2xrEgV5s!k1q$Pgc>coIKqo_H_Z_Y?G$;B95H(_&iE%aQdbHkBZNcd zLR@~nY{TGDXS7>tU#{d*{l(XKuCvVIaxETCgo%r)pZ@dJ+->wf+}Lj2b(ZC(1ZP_> zRQ83Yp2`JCN4=s`db4utYlh@p9z^?kq2NQ#39>Q6dc(sU zH@OA|bCqv@(ld`)800Jzg$ip>*Jkq>@>3D|&KuFqsm%K%i@69!>t3%yN++<}e^1ho z=F-%s##NPz)4&xv@FK%n{LVW-q)#N^l7!A7&PHg!oEZ+l69UKqSN+_w2o+`U8+CK7 zxeP%Ss<>7p)Y{nz7#-3A7)%wq%o%Y15>7z!ZtS$KDQ4;+CB2mOnQ;8ty_P3MWp_py z81JcWDY#syhSrz((-)o;%8Vt+{&w)J52&5xT;7@$S}S9GVp*lS&Uk^Tr~v1Om){G7 zDnR^W(Ep%Snd-%TA;uX2n22{{4bv}|nLhTSdcc90xYXyt^yBc_l$jO~T1vG5rRudRwF#w4If7CLf* zPPsZ}MA2OZG^mi*p%(0{BJ8?db9f%Ucp|PGB-&ddKqZeSH5>_zI zCSPfJv6`U`5+o^&*N}$%UvY(BWp~+HGF}0NbE5$&Qz;BpFQ?O@ifpV;82vlb58rxq@tCFUMwc}5ge~RM_rBqj{tO7RM z!%5WyTLIO^$;>vi8hf$w;cAkcr)tjz zs#?FK4OG=9WcXXu<{^j`G>sg`yaI_`4!ChMc4V-P<6r?n?Cg-Wt+QMPllL%VjH;Z~ z!MUhm#b|Dr%Q}yxMCI1;!s}Elsy8h>NYf;}F&1;3c{-RFs*`~kuI;Q`$(cf87dx^6 z5*w7xA2K_~GY`zs+ceFTvZmYoYX_(Ab9k^Wwh8zHM$iIcF+?!^n;@IScooE}Gaebg zm@m#}YispqFL@=UY*@`WJzd*`=AhifO{pPpc3AR9x}4guj!YO4zY3V^8k1I+*^ zE~uUZ2|7epq!>)5d-}%uSSZ3x!56!tS}IXSztYe+tA;U7EIFR9q?Rs!28H7%BBv&7J!>5u$&ch__WX(=BkRgs+;%*+Y%@iP4#;%FZEh?ULW76Cbu@4v(=wHVHAiWJR;(z7#eF$5DQ zIPN8HCbyJ$WASZ zFYJG?U%V2r{8Im)wWXhd4~ny# zwBTJPm<#|@CRR#_O9=8j#dJWv^3pg*;;cY~uY55jDHa6r>&`JreM)qZ z84Z!Kj!-*=u}i$(-cmbp!;(qEmXg-mU};dk^7jF80f!h~3vdDPWHXD7gjpk$k{zF+ zZw|Ut;ko(Hn;O{Bu<3(*^g@GANaabg97zMoz)*#37DK6l4B<-)!T~>X)DL33rXhcV zygtf!KG;SYgMO%;~>MYiuv7O*`NJ0Bn9UoeoSv?UaLmlG`;&pKJf{ zI#J%dh;)z1x`EBR7m*e8G$X9Q@caS6-*KMMGc7C?wqp~p4m7R;Jw3qckNKzT$U0DU z%Dd`aZ_FCxAD+K8rgidf_@_)jdjYUtGkP$cKIlHVKwX-XD*~FGguYgxt%$>^C>bmD zeWjN8o8`?*JenTX-(d|)B~lopmY%hjyiAK+!CSw}Sx zoq0ZJi0T@UtI8N%b_w+&XZevAjofBg{a%*Epv-+-oF~o4xNWm};t#NIp6!XUIhbGN z)&1NEaRySGej%#SZkUR3zi8X8<=*)R<0tR4_kJ5!&^2){;PLzC<>nox++H3Osdt-j zWrL~)^^$F73@J4^OYieVxKw!64T_eR7P~B7W#|!v=hm$PS6>55oZnCU57zW0SOD+0 z*Ujrw{Lq%G`>nwJ6`)1sN2`={&A7Gez68;d?mV-V;053)x6~`Esw={{yydXAW`u#p z9Z-4B8=LmSK_a-nNsU)eOQfo|ub1{eP~~q+NXIPJ3wUW%2@l z0C|Nji)XX?kZ(ZdyS(fXOHWv>9Y7kIx~Uy@=4SHUMwrU4HzzT;g7>1L#=uZSEgkSh ze3mhxG7FjlKiMZIfJkw!`%Z{>mu0Tu7KIh{AHEHD=q9UXR^Rkqx4zQIvC z&K&JwN`_UdLRblu79Bb4T}s_KQdAZ)To-Vy)xWz{Oc~>w!q{C zziLAoS06LldcISS+r;y>^UuVamj4@l$DB#$`7Qsv?)M2omDy47!s^jTSM&067wby( zT07U+G2}dsw^`pUmPrgEUX`x7___U~;l~e`=ek)(s)u`6zm37TXx`Drsy@G4GvgDJpJiNghzY%)_O-!f-JJ0Tx>!z@!?XJxvWCsQ7+svU#7cxpgKr zJpqb{WZ}7Jd`EEqcM|&RpQ(<8Zr2!#QaBXRyD!a^tR$`DfArZ*SM|tH)^+`M2~I_f zB4Tq!ES}!g{Yqbc=Nr+MQzbzhQucXDG4T;$;+GgG;Zj(VsVJ7$xd0E6CBzlGq{zl> zc2OCFizQNJ)R?RweePb-QBFtxiV~r7RzSu4lxqhL*(8b&98B?qjidUkO43$xMWDN} zg%>P=N;yf_4jmyT3XU94Fu=!9{g&9Gu7nuh5h+KMS2QLj-Q?5@@*f;+aM-@3{u`n#_`MAe| z-bIgDb$1{I{l$0pX>T463}k2ST05cNU;C)zgjG>H+tgY&%_f`fd|+u^#aVOJarK2(JwWG?;7gSjlO1WLgSJ+E_Yy5NKU5&e+a-#ODcuWcUjk#EurrFqVdJTSsBMG5cUbH#@2pe9pwDC zVAyhV1ZoS<@RQdBx{1*;8;74zJ!HBjJA7Hzx;NB|#X#FoW_LJ;0LogelXqL%V|4z6 zxss)I6&9aL-Y2B{(L|{B5l{+P2GxfOs(a-96=z7}dE49tpHQC8QwiF@sSgG`2G2#{ zue`ZD>KU5Z#&tO@OfilobYYV>$jLV7gkEkFluLL9?DkQA<)g*6Z!OauSE_1}dVZ)`rhm4X zlT?}5%iVt8WFhzmJ>=q1i@y=ixY-VRLPzAQ)DF8g`qPOyF zFk;Ioly5i+FJA|wG9E$i_e|;m>yOR}nn6Slz}r}7RSO**bw$1x>T_c6r z)b&NK)X9yHgOvg~JWCUqVJFiEDpv>LV7pk{$4gegx&n73{22NrB4vN@7NKr?u84g* zA-2M{Ge@+3XNAy`-RE3SpLTNWbH3~5eDdrW=Q}>>N6@(dn41^)w<)wCGds5TN6fzi z7F)-Pwm&S*x24_;wHO2Z{B)J;w?4c85v)Ho#U#z%zqrQ6f}6HGOMCDnZ@&pdau^1c zo}!WW)IU?5H?jh!}( zPY@CHbO%FnP;`8=e+H1m30?xj zfH4v3BraU0b!t&KqR1>{1`^Xd;BIBhO){P zWP5xlzPu#9eArMC3cSW!v8^YkCx-)j>BVOz7)d$u{RgTUcFI_{_2h%1(r=CPMgBaw zw5p67+a1~X9JXW$zir%h?Y#O;9~T|gF$grjs8fS_+F0bKm6aoD<$S8}|2osBu8ipzf9s!4 zk)_8_XS4Hohe)u8h5?Hy*6Q{^Ph54PT2@cuEsSDnYNu%xB2p zGCiM7uhe8=KrJOf6ktKMWPzA+|$Ja@phasF~!Gl)_v}Exv z)JB)1V7^IWv93{OsY+#A^|jlMukQ|&qcWh}#mBLHEx$s6*v7^kdLEuPF@fP%kK!8y z*s8*-Mno^K)|6hzJRh?h1GUkYE7@#T8fK48udj&qRV@zmX;7s?j!_nWtJeft6qc>X z{sjX&I>tc1k@%RhuP2zYGxZ#wgKnqw&>A4m?}*D~IWoxyFSrXeGsMeK2ifv#8)`7% zcu;NBuD{~5S{4Sn1Z82g_B(7apRtit@a=04T}vo-!`!%*PLzYp<~YQK&|`c5!Ju>{ zXbmX;8)a?dKrfSey8CP`L0NojXVw{tuhE~~sA<6I;~$xa_5TG?8!uu~Z$J zi2*gGvFV=-@!ei=PDOI%6j-U0&=Wr<(qEo&@BC>?{9Pjf+2?dhGpoocx>T;hBOz*P zXX07mfzq^$t)bb3SGvDhD1D(D&^z5Lav5Hja;b}Rf$=1xYDryVr)c$bHI1SIVI|ab zz0k1#!rEb91jrkiIT69D=21lO-q67>`h*M=~v#r;+viyBM)#t4n84S_yFH)6~`q8d7fCc9CdM`5wv zkIMWDo?&>8B&jLfd)RV4sD8F))-$N(19UAsMw)3fhk-}U*Mpi?Ti5IZn|CFQe@!|U z%DIn`c5m8Tg(n2{2rkVp(j76UQNY5O#&%N}#0o`4tpOR$t@iyFP4KdcUD%SQ%iSXN z&%@hjXw$Ys4ZD#9%SGjeqqa#8S)KBli>%gsqpjiVfU?RayA;Zn<{Q59ZSq2Sv3y(g zjR?vXX-ZC62na)c23cvxi7C{|<&|62h3Z1(Hk16e?zpzee2l=t z^`vIy-p-IUEjxJKj6AMrF|qpnF0%8C5sMnvbO&%I$jJh^i-KZ#bL3G^eVJF=EoKJ=;Iq^T1KOl3z$ErHmTp6X(91$qpjw0PZS}tJdX^k=gZ}#gZR2e~_ma z7Ofletz9M)BCHd7p#df=_!ff|l{GIG!N`wJ zzpkl-swfMALU*}Dp)sy>dK!%@G>R&b?tL7}-uHLD56hp*$NM*-_k~uVMkOdJvIW%8 z-1CL)bk$qcTA;@7h zsuvo7_3_DIiSWe*oAh(A!se@p>uuz6=3|_bMPpn252RBf;W|;mx`*ir7__WwGc1sW z$^#M#!^vrsR^kXciOktNm|>{Lq8MDXzK@T1M9*z}%Zh5~AZ^`Fs^7ew`Lifl8yZj$&a*=@-g1 z0;j9&3XTzRSpF&%4H`vXg~FTm=j5@v}KfA1n3qx$;rXPM^8m3M04-5J>KF3@VAC$F8N?y$8K^C{$%!)%m zkrMr~*gS#+=YnCRd0)MZl4SF?DWC(~mH_%#?z;;O3N$+=?|uz1x^oUd-cuv4%hXLL zIwoz0TTO$A9w7>n%&85llniX2Zw3+k*52_<+aqoTS|jPLOn|}S)HTuqfH$F6xPL>! ziwoLXeM3s_40^%Sf7eU)?eE)&ZR^r%+j`q^U-p6Jn510_!Pe`~y-=X-q8=(garEWE z^HuXHkTLvoC4VrEBV`lm1;IJabyrO3JQrtN*pF zc3D{p6)d5Wg-VQw@yoq<-sQa;Q9oFx?D6mf`KIbFKp7G{(4lJ2;pTFVy?kwi5ZqRe z$1%N!uGd!Lu_8)Y`r#|;HlQ!so~)77JJDvJpqnk2GiE{RHs5`f;Jmv_hdVSKDqx33 zvADgIFB7?rGuCuQ3P<_GHhM;%47n4=ar`*Nk)+_*Imd)sTIEsqMCF&7LmU`R;V~BMKhGdca7qhG3%Jwg>1Ve04Lh>UP z`oiGYMZJVeaBBwTJUD=i@qKoA@JnBze=>SqU8P&WtXCwck$H0FkX)VD{M1Jw!}Uv$ZLH@&n`PU9S5Cpjc4 zp5|rOB5iLv)PHZl%Htm*!X6p+H=Sma=tTNSwj1iD)RPUMcq7^}j8?Fai8+Ab3*=bt zyv1wC7BIgk$AG3;g*$`pzz9X7u$-vQGF8TP{a8|wp58WH1Kk(*;Y|X6pX2cb<|giF z+W!(9e~(Jpbdd7D6-oB}xWMichZ3X``y!UqTGHmj`rh=$aW;uko7zyh*kd&>&ihH= zo)u*M&Xu-(SZ>w5#G-KaB^ti}Q{N^^tA^DZ)Hxz6GHh3&Sd`9~v z4A&XDbC|hP@$bw=0eh)dsH zm$;xgKMzq*h|J6PB-tsY%+jPlMc(~B=^Nx7;>+uX9cHd_SPxHuPfuNKUaq8hWw1;L zp=hI+d-JdYb=Dr1QBnfQm;Oja;`Loa7a$PCBg7!P)c@?+Y97a;rqe7+4$r1?P(aP8 z$ubaFmYmw0oOJ2oqZg`&gi!s@?|RkRS!Dwhk1;EZeEtb)uv1CEv}Z#;N`j33HS9o9 z=A{qlkGzxs2Q%Q)5rW7X+vAh>UYioUd_DGFz+{}dJ$E|nt$Xv62uerNZU6xE8yR0| zj=^oZ^cG56e?spBwuCM8C0%-*?>8*|zkHF(*&>nkK0lFVznj_>;6IS0a!^YjxuqPV z^P5B&Y<5!q436vo9azw#-+(H@pD7swWnnj}5|1`U2;EO_Z;-_D*?D?n z@Hd%;y!n)*oP{x&?|(@73H-i34&t0=i`t~PnbrQ(Oz*^^`38v;7r(vV+J~aiuS^Rv zfwgj+cfZ~hcIg(Ric0t^#HyIM0weGe#rGMBtgtZ`eF?039>XV0}H1`D9pQk$q;rzt-6z#T%3e;5m>%eI5 zr-Wd{c=1lln8|d$RZhWi+g`8^TLLf2BG47!Z>_)QnL~eNllkG8p!E&90sNLiSFbA2 zFW(h5={V`AbDW$+2e+ToN7uWK4<{3@U9HAbkrtj>V`U-}W0ux(w7uHkZZC1Rb{oN! z8F~+6t$)LMKjH-<58y(W@qBp|vka-Ms62Ish#Q1zefHJ%D9?7u*%C<%H*Q8M{TiS_ zFnQ4dvnKGalmpmDX3IG8uyj3CT$ajlw`J;t2;autr<1~FM7ak+!^GC4a$U0^Tm%zH7uZHV*4~pWutfwl`M;#e6#@X`)0}Jn0KO9aA{Px{Wx!ZN!@G zntz4*NI)O%v5S_5DFxN?NsKzNd)?Q$m37I9ranh~ye?)+D96tQ5KLTfz)l7Itmowm zNWM_}v1egmA&dO#p0sb4V@TumnR@HKJkB`2gfxq}vwTOWQ(uMoSWKCwb)U*oypq== z{vT+yQM*3eZ)oPuCtCXc!MQmESAOlRO{+RK0;2%UE+v#2-Q2haj>5ZoG6ee!(AYWD zi5qlBM)^`Ah6aS2q*L9OhFOnZbil3)ej{myHOKLHla

jiI=RFx-*f&Bw>7%s$b1SV7vaeky%jd~E)ILvdSzVPp+1T`qy=L-36#ecT!_7r zARi_OW4c~^{o{ikqrG?}=ejy-xo< zbCsEy2fB+}`b#I|gbqpKG9!PbD1Oqlf3Gb{i^i1q8Z3cFRxxf8>6I(iIzts}Wh)pW z=FKX~L<65oN$ffnkxv=J)TQ^qbN1qDNcF6}_M0g!`Z8-DT_5O$rNq^Xl;nN}AU^at z@#*@5w$V2)DUk;?meD#I{{7CFqNlXH_sg;8F(-GKwIwl^m{U+jBA}p>L%7o7*gh}^ zEB=K5HW(k42->=V`^=Fi9+nxbAQ1aPog=NkC>*=4Fp0$p$m&#D_aL+<&M0YGRT^qKY1|KQ=;u$y_Fy%s=2cV{!XIjE;Q5wu7!>_-`- zP2UQAX3Ty&5|R1Vy7%e^(q%N%v@Q$wz0rVYQQX@EkgL^2O2l`mWSHuHl`40bedl=P*{wWsv-jiDv zvzQI$p`Ap>^JHmMXnrhEQT(Z}a}vC^Uqko2&M3JBqcCuLaBh`sWaxSNHFYp~k}UVB zUTky$6^txTdpp8hyTEapNHw6`kv2E;^Ee+tqa;nGJ$H+1es&4^1%VL+omXuSBd(qm@ z<6QYayI?56(j9q{!s?j`!MMY3Yg07W&$P&z@rwJ*+F^6W`5-!xlrWr@(Om&2>*96c zrSQmLR=f^?NbVZ>Yr>ziT?%s#0t3dl1ozOyir!0F2M71w8!^{L@nOtvCy_R1i-fxW zS1)hQP4$C#aQb?GD7m>bZy_tB^R%22x7BWH~$6Hhkcc; zIp*YeOOQ?;uGPL zAkZRyP>eI~ywG%&GO^2_bLU&BI?`!9qlt(>YD#gMp%jUDhkIxpA6Yn^}F> z{BFs@0MjYEGczvqOX@B=qxi$LCk8MAdkad#WO2FzbCnwwcm-ESo4A#&XocZMJ84< z(+;b_H!q_NE{>x(eM$mNA3VD>8YCTH8d z4_(@~a(bk!(m|Nq^)j_X3o-b`RJP>9>jkzAhAsb$b!{y7SL^YFs=Y{XE~&>xUWv?? zjDNf#Z@fmN*n58aQ!4{zu6s#E$tv-D#5D`2%>UG^Lu6bs$GPab2&R7&g1O2abRb^yUeW$r7dn8S{%kNxy?)v{i7E_(tuwruUcXeq)O7v%f zZ^y~R`9|DumT~bo8C^lwbh;`oc;NY9uyX3{uOG#uL5mB??>)cQ{VVmHKe0^Rr*qiH z^h@$fT@89hST@KTFJj6$`ta@E8P%`BaSGNau#N$;iV>FcMwdXG(1C>2iKMm1hJ z<_)Cd(j(YThN#lnJd~9l$#V!;oNoR?!Kp9*Uy;b;wckAzkIq;7R51{^>2QU+0QN!- zi8q`oHEc$uPEKl!!ncoh|J7}VxA>3Gzo4mx$G(;Saq#%irZCZ*UO0rk7+R6f$y;NH zM7_^iza%m*dX5@CF>9xL(J~11L;v||9SskLsY-qiC@C8SE`ONy=7;1h%Q7bh zme+M-*<^yN#ht~LH6E35yFDJ{Zs>KH`$rP>_aXC??lA%a|M8F=a_|D6c6Q34Q{=y^ zbD3F7X5*36FmsR8-G9aLvp^ZwQVaC9jd@mT+YfC4V?dF@rQ^eseJoWh5Ia-{f$Y_+ z-RQn4%4(a4Hqc^qM{JeW5ZwQm3Z5Rqg}hIw>y-Z-G#6mbQ~TnI??9uK!478`#56W^ zG>wXBSks|SyDTH}R4-3dGIk^a3?OHjl}V&UU4KPkNrxS6E&NT^Ub#`}tg%#ytkpG3 zjc%s=MJZlJIoW;hw)z|9vEGQ5U3G;6V%e>6*V%U8scDFcaAM{O;l3@{re0W9-t&7c zm;KxAvigyRp`j1-KMKXu-&{|>t5sF8@dyP`4S+Z&_Hf>t`E~H{b+gXTFA8#P)g98z zTClrCvi?JJmz?fJDNPoWDcsa2*4P7!>z_|6SM_$2(d1^b%YGoB15xGmoIUEZ@9PAM z(9PW+>As<-(KP*?A8F6A?SA~8_Vepu(7k;2L5I8V;%{Vc`<3yIiwf zSKa3ygx-p#3i9bgV5tCOWZ2;K2mz4U{Qf(|ww9)B(vnZS5_b*(gu6uIz)@Vdmq7x% z=5A25>ov0jkm;yPQ_1$Gx?}+kR@`%0))3)|p2I&B*Wfq9jz9Vym-wrk{p)v%)O5k8=l79DQQ$cR>hy(}~n!(3$9pVEuo zZ%s>ymSFCyE|%WDzo~&e=IrZrLu^B*&7)UXdiwvS1okTGzPZhjtR9(HDuPB1;)6Uj z4jQzj;rRnA1iA*Wx;xpIL?MZ;!goIRPrv>8rQc;W9YQOmt)eR~e);ltdhOqQ1KeZP zO5W(c70zrVQF*SWy)iA}To;YVYHYf7Q_;x3d3J-6q!F11F;q@quaSyxD!Z%^m|DO< zcM!OGoue7hVDCQCJ^1BOyv3tY+gm$+5`HYPdvwa`f6v7q?a=erLJ#vXTom^pzu_6< z>h6+RN)yq6@(Z!qS7g1u$|3And$4tygH9?Cgo56|o8HW1;KW!ET=@hL0gC@Z#=KXpfBYbk zqr%s-dtp^-fdX%E#NTwE0|Px>Jvz{`SCDu!`zG1Q zHH4d#M_ziWs?Hwx{AStC7MyHVc3<*V+-Ny&HB<-lr^=A^s-u_8T^-G^u;iUO_w(7l z<4h;!sou_h?YYs?@=`k5b@|V(!liRMl-_nSSdP(3uPivTo?WjH^bdlA_O+fV_Pzz< zJgt6KT7R#!A3AEq{g>Tz)mZ|73ZZ?JSHmM z0Jn%A9&HIWXXtr`H1#lf5(4s64~UkeltJiw(+H~0$i+-XqS}k54dT!!1~li17r@f5 z=S6I40=)^GZ<|k#`$@rdrM4O>NTfrquk4`(u4IH=o=NDATFh!FlrD`~U;8{9G^1n| z{&0pib&JHCl4f!iH)1Hv*rKZLdxFIdlC?ypNp34Y^!#VbPI^U`7U07KmCH=BXVn9- zKU+D{OS-hiEC%@3m@EZgaVE3Ib3#7x-w5tR&&lKyt07GlyD`DhcfC06<=^v=_&$bC zjhNGh!s-FQ)vlTTOz|(Yj@R@r+IC&-UDnWBLQd)IjCq_pwCA?)7?py{D}?**wTAnR z6Js;yFNlIZK3D5~O2i~a}?fj?b$@MCK1^>V($4_kWz`ur7&WCNpjY1}O z(n2}TLW(m9R(XKndDpye~&2TJRm+k{?=c5EdW;;)00t9F|{{Ni(Y^)RwF z*OR(PAZK%d;>wMy6tL!gV1Yt_cmut-_(dKN0(#q~(o6edLslII1^HKA^i;t+96378( zI#~<}31)vRF{FW&5QKk!DqPOZsZoJr0aoo0E1wwD+xc|0&gjinx z2qx*_@Gp?DwdHHCWqQG-LDGRNqa?^HiDe~*!uNUPS;|{D<ncw8U*d>P4fK>C zWndg9WK$<(KOcx0#~;Yoy{kF8*lVS_wm^#1UaBtj=+lM*b2mWUxuJEm{;F|Y3D^w= z+nBotXnn+h6^7{ekdn~g855yh{)sFob8hnZI#WD4;iZL%b>N6HdDG*w%iwK;mTkUl zQ&V5E19!dI5B9#Ey<%-A9{z0b{p-k6*=C85R{@_ZGa+Vk8z-rY(K-C(HBSvmN4&7^ zfc2;OrattI3-5iI6;lo`C3Cy<4ZSrcMv}AAyDh7;oHFw)c2Sf#+KsE6{RH5N&$^TR z6CZm=h4*(fEh8E)lr*_?L_SYSRz{b8Rb+qAMiAH;ce^#RF4MVx=zSu;lt6&Z-CYf$ zh+oKF=_P$lIcx5z0ru<-1=sN=p zR$n(5D|L?70t7Z>Oj8(8PI0`Q@XhpK(+SP-voK?V5~&B&?DH*#T}{1?@dl-Jr5~qo zrle8id5}ucWnZi*ldV=6u53WQ2TWVBe}>NoDBsu>BJteH`aSJ zclL_2<1KZX8mrUCI5I0tbblb3u0MKA{Y~|B{^rPBnrx0x{9FemY+A$#VBEX3M3Kt> zmNf)&P8$?_40Fo)UHm@$X&n_5FFg20&?{pVg#qRA(L3k~yfZW)*|cm(iGrf8%w55w z;mC9ffK*9E2LXuUF z;S+Ea4wYC%MFj!KqLYDFvj^?v4*G6Y)(~g-L<2W1TvZw>#q57Yn$1xQIbstp5$}!N@SJ?=DUBI4Epz@FCn!N4H(F>n{Ni(e~Yn0wR)Ebd_ zZ|r-L<5c;{}SC#SDATnJ>Z^d^x)P4y_OW%}w`zaDcbv2&s z%FJ^8}SOsW3$RyGd2+{(f8I2fAZEYE-o2} zc;R7vW=@;n=1_B|+%EjU#shMb?YSv+f|pInn{q$*JIhTS<6mqjsV}zo8Nn9w?6Md5{>G^}t6BTzibo4wmMZMo(_LHN(`8ne zd)n*jdfLsAv5An^UfuKaxh5{8j?jo?P0l|^6QW`AFowc|@`SRbyuCk&zM<~mXmia*ME&T)(FYyES6 z=8U61HvgLQHCMPUFnR-^w8udGzW9cC-ujyI`eN|ww}gD*8wuGc_yT_n-a%t^4^3B| zzpnDaSK>=ad46Kcf(mih;0{<9?kIfxJ+&p3K=f&PP(vABJzoa*hmgNqzW!eGTHo-i z^XlvXLqNR0N6-Zim|EgNUbtJ&U_k%Hlg2*GSRvQt?sg68)vg}*;$GfOvp9IgeAO-- zJfKdyogIa#4+lrT$%zir`mQgtPn}hEuQ79nYD*eW(-PpYcmbM=N3cjJO4k!oFxq~<2O9F1fp`J+Sy-Y(o~2TFuI%YQ zRx&^K1uX9EsT9v!Q|Y}9Yu9?*ODWwYOGo(dIWh@YKtVBf%KS6rat)?vtz3NZwfbDk zn(m)b44V57t*nX6x;#N%FQz)e28{IE2ul9e5%oClae{5!Uvth~hB&2u<*A&}*Sk8r zYqR`HU&+9XOrt1s?Fp=Xd7Q7f$tYoc3~!2f7)Sl^KVNVu3_DO&S#`^`34qc2?hwm) zckdtewbfYRA&!67`s8DA283h4>YJt4^81vX8=E%uk-FCVy8wW43=G+S2tza_ByyLxC8G5(HV!$i3Wn z?}rz_=6(V&QD@0VUWp&ewn5{S?BQ4KC11HEzE%FfE%klbcAM!SbMSRr`Db3KZ*X_R z_c!#+zGraf3%0%gYkYX~o-sQCU@UBpt7G@C3=+O@(ax_D8{GScX&)dEi6}8T+bcFf ze+t<|_+?XfVNnpj9`+Q4Tn*YyZs!uI09C3qkC~-RArsm;C6s_A8NGH6fviknW=Zo@ zsZ;>5om)(fdYtf{`773MKRS>LxmJ51koNfZY1yu{WRcmtd*T9&?x)hJ( zyf2Jmn&Y@;lTyx_6ri%r7Dq8Pf!n5q(Z!kji`2(lmJFx~xg6?js4IEjvV8RT8Pgdu ztH`;p_PbMpljmVbb$IVTy{{1A7xi>KZPnG?Z90dc+ha9%dkm?cxmtOgA~^L!#HSq7 zdY1WgR@I6=lZz)Yxl{**$s-V0JPLLjS<)-FOjRt2@iX%kD1|m9zfEPl^hhK0`cSB- z2M~H?A_UutNCm;&ms;G5wUgmYPCU3;VVOx&^VId_bE)*bBz?-~n@ zb2wx<)Vk~7sfmAFy^r(CaoLGZ7#Y+ek zVrg6Llzb{tEfw$cS4}=^`qtzd$pKy@^6azjEn9jLfgZq7IU}r)&%!}gGMTvBsi617@mf=>=0d`AND=e_uViw5ORqqXFJ&KX5- z(mbM;8;0?|_p6$^hQ7DeOG+kWE{92m|1;6BfM=ja<@^s-gJo#^iqdPh3g)Pv*W_3; zXA=Sr)ai$bMXte>nPgJpf3peRJ&bap_&6rB|EQ5!ai0edoLT%a1@Z=2Y+g zE?CKO>VCL_$e=NVKfixwBd)+v1vu$Pfx6aXG04&Lww?oa;Jd~z?A%|hp0^=t0PdhG zPO2(f!tOwu7fzSXji^t2{BoCdnH``!q+uU)gvwurir9SRq*INID#8TspX>sTQ5(I@*<8+kW^Y7>OAT&;s zs2lI$!hgCb4P&w}!m+>Bek}g{fp`n>iqrxoNvabOBvA>?U`*2v=j-xbA01tzS9OhkTRI}&vHnJ!JLahG(n+rRB8J!;{t@rgwLPGCWzHRKtAp0mt|5!QL(L z9*>cqlCZ?i?X?YU+j<@*#qMmV?bz8vZD{>I^29AW$~Uzy@>nMaZ}BE3LeK@R%OuC{ zsITpOvK04pQzS-j1$?M~+NK(MN76fq>8jd-U;RJVzt_MY0o)7`S0fh?p%^)NGq8d#a0?@>E3 zI0ZAFo#X9nLP1R!M&g`PFmw+69jo$3y_!9F-iQjIj9|wssO0uLz{!n;=#iHh>gAFb zQx|{V+k#k956b%+i2!(Br+s_<*1A~TUsM|Lg?`8#CDdIdgAnKfN=1tl-yDZ0Rs^w5 z%8!lW$7Fo0C>xl+6*|?F@vG(WQ#?X9d1i=idUZYB^^n8IG}G&A^wWb_n5(s3q3F6) zRa%};ZmHM$yR>h_jJLm=7no!C&TmzZSkWg z>XK`V0V>Y;6DlBUhbfIhg0s0)s<;AC^D|7zS=YPylc&X2+5vHvHm!Q4ar@Hl`6oya z(F|}SG%PMtF2V?fRPoJ0R0~;p@Kqnhvj=jXc%4tW+eI-m-ud|5{O1YAhlpB$D@?5i3LiHkSfd#LP{Sl%xC4iln@7s>{pt1#b1$L!g@tk)bx$Qi*d!t(iX?B4YfQ% ztj|qT!G;PsM8QYXbo2!S6!CuTGL}q5=kqK5RXi5t3=zE^+tdo4D$g*XWQaDCp|Fx&HTR;0XsyzHk(HtWR}y%-;aSW z*8Q4;xDQfabAo3(hq7MezHU!AU8oZWji3t@XxzU> zCIqa1d0N6c>$!!*`-vaT(At|%Y_bRbwX|d_{&A$q4S2`-xHTKb;v5x9BQJ@Pz*S;w zCtMRNAKy5BUBV2BC>J6N3WQ}9NLE=wXV!H|c~V|>Ho3U0;1+FW?j<6py!eBgLjHJd zLA>k8#@vFT$C-;M6ZNG^q2b_+b$P@Pb2_QFKa~!%RVYLSy$nI1_$#nLR}Z#TRS&e? z>&fqbSY0*rFnK zcmkJMB6C+ecsbylEP#lJ4_+iakTWeK8211;&~lAYRLMs;*&^}QbXP*W{QnrD< zH}8>%28BeZR}f>#hDwoGUqzDK=d8mfO$w{lu&P^oC9q;5k{zfalrp>9pozl?L)!6! z!y+Qk)s~S$i+^mIpRPpFx0gito&JUhCkedJqMK~;S4+Bq5>xElLEu(SH zKj{+cj^`o6d9jNAk?pL?joj%d11=WZGxOKoDdtc5K|Zip@Y*KO*Y zrA%FQV5VNav2`}ryDi=S-7NF;cL`)|TsW2Q4jr<)pHK95;3olY^YV_irXGth6w7Q2 zr+R*0JKh#hFH6XF}k`1qoiEiLzq0>gM=trTULt;8&+GXA2zNQ6*sLu zq&7QQBGG^4VuY9Vhu38yAV86k^^BwtRFG7dn_9Nih;6D}x_di%JgBhxr>}1Y2qF9< z_5f^AExmndx9gwgh4nE%+d}QLy|ctZUgI|p4KXz%Kj8)^wB5MVi_$&om-Fng7PXWP zcP{3A^X?FHvGA2gq9FF-=J%oQT3w}G(%ED(wY_(%%VKI@Qf-&ZjeRD&LY@{B_-EqE zzVAj}F52+<6(o(NU4{d6YJlI~2fy9V$pFRtm^t9?H zFYCw4ZXd*nAj-lXqVY17(wl*ogQwy9N3t7ljr{y?GK7lVVncke0=M*ZjQf*}NSt1UbOwG$H$Dzr2 zc4|A8$|B?ta?xpod^8S?rO>gt`4#xWVjhNvmQ%@8u0W%qP&hn1L9v}hkV?=f9-B(S z;}|3YpGv?p$uf(Cr|Wj}0%=ibx==<2i_*}F{iXa+jyb;%wy>Ak?@G)Kt?%m>=2Vo$ zpC~gZ<)~B)vM2=uEiEX*)3x|wDk24%3q$8Z@lsUiqwlY!7Rf1+GDa~)hD4E7v&OC zo9j~rPNGrbG@0ZinMG%@5Xbh=lPT58assM+HV$7TM`BQL z9*fw0gUi(Fodg;N&ZkTJy#fvFdO%*(<@aw5%LsX-Ixx_TrUDv+LLm~7NHSYLN({!R zFldlq*!ThYz#U~jAbgnIY0IeM-@~pni;L#Qt6o1RKW{`f4BXo!Z@#`Abl}+QR|vc! zZ#!FY+yb1X82$P9cBa=y|S0Fu2ZAP<>%`EV& zvv{tOGYzflZ^f5TcY#p=!gbG)TL-UMJw9@fbI9pr_I>R)m2p)M!&-d|9 z_<|oSDS!3?FqohFLo(k1zGf1jXBZ9#*ECZfeg7gf&HZ@iLOl>8CdF<1j{AUfi473% zIt{3w0HnTik`0^z_dP&1XpH^|4M-qvZMTrVECPi0Gl*8ZC(UX4&fs#iH^#9+Z8Z+y zd;`t@1(|)Bu${m~U^iFkc0J9s;6gR$zR~5d6BOyA2}B{Nb6@LcUh9k;T5@9|0t2s) z|5H?}@7Q*}T|W@q|3zRMWLC8bh<$nF^2wZ`?8X3`k^6rkXBj=8oa0|9M|@DH(6aKk z@I3E1Q=smmWW|ByuEp zXtW)AUP}yqnwyE3jdm91H4^N~#nyDNgL0F(kzAMGok)P&-kB<~`u=sePEmZr{DiIa zCRDFZ>YL1|I5=>dhUCS3Gw?T)r-499$VM(@@e;jv*%;n$I>kv_1;VdAwg17nd3Zv> z0$m|GJ0F{iy{s4fTmaBBpw?ZN3W}JB(|HmVXTnODoU<4m=ldKtrkSGjt)LIGA;O42 zV+Bsh^Wj4;HCr1Pc2H1{!x#ha9kdN|9*A^PH6Hh9Xz0>BqD<*BBc&1A{!p!1?&&`X z9;`GhKM2f)F$Q_$Fh)O&Rj{17Xr*T214M5|AxlgY*7Z-}Otizi zO_x$cCD=MRP`g%``y*ai?%E0=|75u$R@1ucB8YozjT*5%up{znAp4tFs0Y)7wA4<7 z9OYPaU5POA$)hex8mUjKKB};(?|A(vw9Kn-g^FNgjt1Vi-6M(uGAG^HYpBK!)AA5Z zBj18)B?v%+&mS#JRW4SLx&oGw2PuW3%fRLRv)UX|lqW1YxAYu$1=>O#YbZDmgg6_3 z?9Z|f3bf)`8bIPfS0**#B{y%*QfwD02Q|euLDH(O73KkmmmQ@#@e+raVMKOlBPZ5Y z&fbME`_ZoB;iq&!58&|c(Dl>*1*t>I8U5viIL7?p(1aX)RaMBcH(*&&h-sF1nFYoh z7bgMQj!T89(mp+N7Zc5PFqPF!IzFFZ1c`;WvJ>3P5dF_~O5%RFqfh`C3)ok8+3$W9@^ODg z@N)hBDEuCqqj0Cbss~i#g4R5a_}d)0c4rlo;=)`am1!s+p^3a@BVYkqb621#6s2wl z=Yb{UG8u%$VGMfEB)BAOMD=p=5L%-V`;9w z*H$(r;DvQ>Qt{=MDC5{W6b)L6ZB)i+ZDsE2sJB`=ZE(;)nQqheThZGzXdr}xhW7o~ zBggR4WJumLt89`bWaG0$<2ExK22RNp5{JYo<^ZWkLpcbj+**veX?{yRB4H}*H{|Z4 zl)wdcVwV+M7iQV$WxvEb6ku=axoOBjLx>CiflFc#HJ2ztAH$SgSr9jOF#Fgb9_iP#rFYrcN!nS>DPXcZKHbnr3QFLh&NPeMO zL&t2k$zoG?25qxTujuD*FB|0vO9{7So84PeoIi!A$bT;}3peYWK!a4I6$j;;rYa;J z3huBy3AR<{jF`w~xebC}U$G@67b}k2{|6i?y&Qu`Cy(Cxrsad&@TQS((IaBJpf|T^ zlBP;Ma&m^{8k+fWGGKdYiYm7-)!f?o5Hiy3J(D zZo{J=9DzV=b!T*V@#|f-y$(P7;Pzpnzp)`~l@Ihs_cw!3ZcaZlL!mu-SaSp(J<5y* zYmR{#3&~7`V5Y%GQ|nfTSLJK45xq%UQ#4jE??1$&m~jfkRptE@^w8(ty77qB7dol- z^%b|DlPe6FE08g(p_x7KHaE2#e-0@`D;V<6PFrd1Y)#OptFej3wrNb7Tf3x%5tVi6 z7^50gJ(Gp!iiW#euI9e{Ch1Pyb6qoWU#)Ope8Zh0D)RYpFZtIB$Sp%2ZTJWGP_3Kb1PtK|<=*4=nSzm}BT6#50&;nOx z8En5;CUly-zwfec^1Cl^s$gR3QW>L~!s%X!%F-={yr7?5Rp{~)1={R&sbmvVYws&h z5gtqqBu~dwlEZ``Ii$lt=ESOiH!YL)BSmBk)|=&>h>;(+XL6o zPSgcy*8UtzJYs|gz;Fe9xb4=vKLHRqSU2<>xXUgFIll`lmfz|hTAb9C9U7}!y-$iT zRVjulH1i-hdQC^Lo5ZGv87GpuH%VNv(c!Q1`!fKM`<1P8hfI5*G>nsFPZ8bF^9F@6 zxRJv2^VCNE|DRQEjveV9J5Ug&O1a^h`KU>#h@$S)mXv*vJZ}zZVIuu{ufz4}tp3@g zFiV#6%o@u_{hi5>rfX zJ$r)L653BBH1~C7w&wpVXDvDUx~iT}LcwJO2|wxk5%nX>Br=llN_Ecvx(7DK|1|TLb>~NnzT6$v&kHt0&hJQ?qs~%T?!a;dJwGjs^WaOrxZl&xlFR~( z`2KYB3oO4xlwKipJIfIu2r=?x;C)K%|DvbNw zI7A|s!l{%H9jBC_+iBheCzx$g({?7K>RRD$sQ9w8EP@M#T*l8;eO6W;Ny(xGxU|fK zkf!k(|KX4FQk{R|55;pR)IbWHiabV6X+_}D!f6(lCUP8eE=;tObK+pRtnA0)t}G&e z`h6?QJhXsm;?RmqGaCYz#&#TA&OmfBu(?}fe-I!dd_?YNDl1)c#!q`6WJBR}a%+;9 zuB=k2gLp>8tRzz&Bx9OX8JbyDrB++lJX&&4(5~|rT9Z^A6yM;V@&Xe)sU{3lmf$04 zW*1oW*n+`Ib{HdB0w|b}ilkM9gy7#!FXWwf#*#aHV)rjX1#dB<)nV%Shz>2u{EXvY zQt8SGNXnz1G6umV?0` zEr(aKZaw2*z;zpiKa(fPT_1`a`K7P7V@u@w@88Fhr2k(K@hrGE=lu69RD%mT^OG%G zpZouxH!c>IyQ#KQSjtk(Dy)8~`|W6*o;SRu`KRm0+U50RE|q@du{ZX!*H1i_!JoaH z)z%!iwmLtYQf+JH`>(1jb$-W7^%R)mKLAe#7M~BmZ68cfURZr_kjqDGJvd4M9Xy!w zRG2J5k6(n7C1~j-+al?Q8VKk|lb`)Q`3?&d7S8GHpbBPi3}hhp>q8=IJny82UYOsV z&M!~}vuc@9I;mNwO|wgnKGv>3(>V)uC!Mm-irU;5d!mCb4WNT5_|`}h8x~FnRKaYc z456^No>+N?gP8&h@l{h2c!R9_lSSAnOh2AQtr@N7kYEeW3KQyjYRQa({Wc@}V-H5K z!Gj0VgfGm(0y4^3PrLxz{JSWJGtK$PHQED=fZ*yTu65#WI)bVZm71zFxD#g-l`l_ptcsPuSz&T5>9%6a(vo-K+l0R-wPL*nS_kevi!b&Pm=TV%WEEhQXG@~r|o~m?lI;`mbN{p$*ugN@@EABK=N$W1$ zJ^DVQ{)`4NWkOtqDAiElV^)0S1cFZGjz3T|>APpkK;-Xsx5fssR$@)C;9$w+_&UvY zaBLRhQi7<^x@w#iyDa0{-%!lVuj<#uVLp&_$x$ zm=oNq=4GGxv^n{IN>C70p;G-H8IPN(B{xDXum?-szjkL{Ys>#A>EO$hB96YcLV7Y0 z;gi3+{H!rd$qF-HBb4LoJ8?&xt0_87a|vi(Zi?S8gc1t#>kQ-fK*>8!6opZyXFIU( zxQg+sq>0i{Wj(M|>w(L4T&^I}Ez1LTj1Kpx^M-X!uckR0O@?Y3O*BX^KjD9g)&pwJ z+>CeIdL}rW*$mxXp`M#tSc7|Za|#vKbKLvn$j-F!vL|OF$lB7)`W~mjUEYD|a} z&>G~~k&nI=C2KHCsVkVcId(-g%}NabMKwc0p4A|lFUh}(*Wfd(Zg2wR)zkcw(5&tL z-`#jtwTGp;qTV`>h<|ep73L4mQZu)D7PLKO4QbvJxzw?->ABz2B&D3fb0v{&f4rF& z@-f!VnWx$lZwW0WoZ92+&XBzCi|5Y~&CTaZ%S$6oTya8-*eV-fku6<uep;{=3T91~LiWefu{%JXf+P?ZRiJX6>)abU}9P!MT$}TL(S4b3gq}Q|WaGH5r#&Ja46Y3T2mVHkvtPhuPtGX&LFBX>L z2XJ)r99_(X>-3|kENA(%PmSp25_xTHZmxQtvq*(em4TjtV*+ZspP z`_fet(gFv+Sd+4uBu&v0;nmKRjx{m>#qUBwghyAcP^Q)+kX}ax-~^3R2LBb8%AvZRFDyWx{2kBglyH;Gq+yt%ZaT{ z-bw1GYro4o63D>=SP#f4K35Llo%{ySB^yhiVQVtS=ld!5Sf{3l+4&YZ;pdY4{vVa! z0zCWrF9pV`^VUO#gc+%~n7=ww2_GoA=m!+?xB)VRcGxVw!(nSW>~GJqTV&&3{1)0o z@F&>*fYInb0K)5#?9(LO7mnuwDDaQpsqjv4)6Q-OaN z%Jupx<@I>fcdgPyOmHgF0-tY4=Qq+ZD82+RQs5Sc)-d!pt)f0MNH#Sv|D7JptkZeE zFVH{vNaJsnwP7R<)@q5*6M_$MM{&$$Fo(rW=VH=eveuz9w16xkaKZ(z{2It?pvcY{Uq!?uKKG4Az|`&hb-sdlfVO()rRMwK z?6*EbToQPShYgUR_PDYl4?uCCb`)(xnrSD6e1Zrpm@#H_#C+~uk)ojfKFO-ZWc5e z;+x;bcL=9A>g9Thxeu`DA>UENMgY|mbI7ppr9I9qp;xDN-|Zz9bxWM^Oj}sc#n7T}zyCU#J#@E%g^npF zIs5oKgs0NGCZh(Nm9d8)wPyfR*pk$|7+b&xwy(5JOjrY=FD5mYuMm=22M?ENk|{~U zvxaV=u!ap95X9&@Lhw6}o5A>O-@6(hg82)lg((i$E&PTy7ymiY~+Az!eLI9;g{VE-0MVQJevjVv|X} zfT~mBB-yvp>6h`K4N22Z=>J?_?Q8BZnW+04)hYz_=TRO#}q#d0aT@1W$?z%;_vr zuvRZ$t*Sc3?>VG`Y4o`q`O{rf=Qd+rYRj3g&hNs=~eNh0&!oG*6+*(L3Y9EohqV=ancY^ToiiJUo1|D4f1|B8e zT&d*>jeCgCD2svQ_)t~Jo-jOBXC0fMA*pe>U#LdghkQx-XkBy2Yoe3c0F<56*8b4F z?r%6*sm1QhAr{r^=^hvYB2yEBLCo({V3yr1nldUE?GtsAWE!IY6I^)uq_j(^ua4U| zEOZ%0jp#h?qyUzMxx0XFpoeX4Kmuk~IdXSKx~=-mJ0`7{XgX`*mv3&@i#7AqRV#9T zs0-{#dg^>ii@xPdwzAS_aNu1{Ulz)sAR?SpaFv~M!k8(JwD5u~6}!K1r*z32&-T>( z9vnwC2T$a~ja7y?6fWqjjhfqIS*6uId|53YfhSw4F{Al((swTNVN>YsT7e6)Oi}a6 zW~)RF2!J>Z|kuLBb{fpApCdJw@xUsP|=W>L72f;8ohb)VKT&>Ys zN4f(!^BL>sMaf+oe2`I-V1{@|5H~b#?b-=t;X89o)+3?6x$tb))Z7tgIr}vq7CbJI zXdIXpt@e}y?2`y7gYxjVY|9PF#dODS*0}1!Wm!;zz|p?+eqX(&;>;7i*c91iFB6AD zHq1bAb_vFG&_vs91Nqy?w=RcOiN))<#;iW|UF~?^!4u&``AdM?q3dxlC{p01P|#eq zExK-ePRE8`mT_ns(5)b2N3L0OC?LV_M^cR2{7S|d4uj3Z&TpxeXq`^k(L!n13yKr^Q zAs}+>m4dIe(ntNfGBT zo%B9AOhd4Yw6}WX7-S)F%_y~YO#;lUZ#)V)nw~~%Lef>;2lYPRy3#DW0izBu1Txa$ zGc=oau;tF^Msks>d)cf93D!MhexB~_iVlO~50etHPJ5`56&ypgQTPpwX=uo&$)jU1nD|9qv?~9UB zFA}8K2DY-=o;PtH?YZ#&|0KnidaB!Sy2TXxCb`+kTulgfd;DS@)n9)4`gnVNx?4Ss zeXF*@HW;f|q%9watX40>P`mOHnT3BaFDz~4-~?JV$dku;%*tT;7AdcI`a`&A(KneT zx4tG-llsi;Q^5sIGfAvpBf;&3B^6TBGc>vs-1vqtniX?!=#=^rFs?(dejx*4{Jaw9 zP1b+UFSuXkvshu6oOnS!@KT+ZG*a4I8%& z*S?}Y|9;#Fo&Nm(oAWpA<^J{fI_{00hNhB&v#hMZPx-YfzW-K$QRWLo8Xg@V#!Viw zQ}B#}jN0)O$T#$v)$47Hch)M|3IGLdD?J`xbYNn5V&JH5wu%Zb! z5o6k9ETj6Y$^iDXNe(DX3uWTsWD&iQ9|=t(JONJ6Vd+t(qx*l~x}?Z(j2#aUzYm)Y zw?z5L0q_r{opl#*60jhJLqe7~UY+MhFnoc;1K8+~d}rMTCSCWb#;QhAJVPjG2%RGM z9q9n3!?tKmi<659F=BDM-~e;(Ih$<~5gjQZhohO-H@4rXjF~Yav&3BUu+- zUX+1(bia60NfTCH7X}IiP07hFBehf@h~NPo>}Cj8Y}phX0_RxvZi%e&N|bzoK^z0(%!UM%wdj`OT3Wpwv}B62K(E% zo;|OiJd?858oOmCNp=mymo~@2_ntN3C;}c^V#D2tQ$r>ARO91Qc1Wh-6{`{{)bZ z-4@gM*V&$kGOc@nOxU&=t01v2xeAHD8*pL1sic)1>Io5kwravdijWUIs_sE?QW0UW#Rw&n*%$B&lgL2vk zke#%RW^u;wkYVFlmn`5P^O&wjdw3ts^*`ltyPxtSs{xShHh})=d#5VC~(-tP}3c!l_x%{px227P^k3TfTESPXeD{&=6)C9X*2{v(4=RwAXY&hk9%< z=p472L+nkeVd+=&ZGTD{R3w@ps3x)O*j@~(lY%QGY&hA^v_eesHk-oaNu$o*2wY{x zyqQ;fF-PM;$Ux#9M`YgC2M!1>rGC(Ql(C|-5i$&E#}G%jJSG{IdK;BotVoq;8U-38 zUvw8{*bqA=6+eG-K-zlHzos=;`=X|Bp~H6w&I3mRi`2 zcjuE@0Rmlx<0V_re*8^%IO@Qp1J0(Wv|R~~XqrI1Pe;oLsxD3}?ovsXIt@toCEF{B zkV6CvEgB=4+#bi}lH?dA;Zc{98%N$ropaV@ZfXP_GHIDi3RP@z+v9U?l&B?YB6!)! zKm*QjuYuN652=T2eO~ruC2PK!JQ79J(y!G!iw747v^LPFFIOuy+A!unIJgWS6!8gu zI0&=$0iX!n&4S`~R+4edBci-btM-|gXW`U(Qw%;`J|qDZ?L)UUVp$J#V=#r;qajgw zh)Doh$AfgtUebjyC_oy!jOH8O3q9>CSL4Y#7xH3QYM24LtL+rotzl2QZ6o>^y=ttM zh6@Yv?S&LU9pN5xrJ>L7bi zF4g8uN*0*xg}M${jQ*+r-@ZTIl{K{bN}Uh5MbP%nb>eW@YjY7U8a=Q~W7oudf-UKf zd{3jY=FlIUQ56eLh`TDI7Yn>`Mo4)SND=cJ(wM;%zfwUi8Zcx%uP(rEgi0 zD-+?ifaxuzuRwhBDAWRm9S1=R?#@eX%mvk*NlmtO?%gW~hem%muSU<#r1zjf#wWj7 zNJtz#t~jW) z?sd?L2(2$GGE90HDfydV7dv7g1b5~dxi7(Sm=6&1*?yKV{C6Lpd>{!Mg!cp;mqxOU z7BZBAhdPbc+I)FFeAA6~O=(uWjwls2z1~&*g_~cZAsbt)NWx!c;?(H2bkSZU?+M$; zS~4{#SYo<%&*ko^!Fj*~M{5c!8iyU#1m{_h(%59N%``CCS#yIz)NG!4B)GGZO24)P zU=Rmq=OO9#OtVNSXLcmBO;=2)-j;KJ^sXJVlRVR!QoMu{fBts6dXdYF$!u?=Vhnko zG2O+b2j;E$Srr+0SX&$X{_6YV`EfovpM;+=(MwSlmN9+NHCQVPs#YdmKC|>SkEKKH zx@?@QF0TS~RJDm}K(5$(}baFR|kyc8iaPM(W>23?GY}^A)I7&Nk`TLt{@wWlC6!Sw@V_uIUh#s-c84 zXt-*Cxc1UZ#?&mUgj(yy%(tF3Uv$$%FSnT0EX~}vUTaLgT>`V?Y*IwRSbPeVrH(e$ zfg!-ZCrjjJ*|8wp?y=|sb(<~#D;?3!WU(5Y7)0$0FJFs?buxTK1Y$OBUkG&rp+TR8{kIty^s_i^cSs7P5da9zPtax>v z<#>aHx~wG%e`gbyNP+hQidLW#l{J9C*T|6_p|Y7CwmbDfc`3L93B>qSQHMNP$Vx~p zA%H$h2Z)C>35w$a4N5P0u}lZ{X>^!uC1z@%2Px%rB7F2ma753MVaHZ#JCf54)1a>_ z%ds3VfMy2PBKQ2Qaus7nNg-I*_Tjgv)rhfeYc*GK;Idd%s?e zEAq)I-d$g3?-~IcKf-no(vpa8hTir1aHA=6fCdu|Ok~zRK*uP=R^TE<=i_$%c9FHV zOpdp&hrQ97vo>*A;JQPEJ}F z$A39Xa;ESR2ci7v)O%@2jYn{VLxwBu5Wy}t!|-&IR^1GzNJ}Au1FWGXSoAt<=X63k z0oBvpSkHJf&L-=!Oykhez^2gp*9>!%3M9Aax^!pC5&i&1zx{B(wFE_sH6A2%FR-((yDLEm`rim^kvWrl+C@C-^Y71( z*B7Zvsv|CLVLN1)jUaL~rSq3>F6YxxY|;fnRNRBzW@T)tbsj@$%A^*y?EB>7{Y^zn zEL{He42}r%Gkj?2r@yNI2y6 zAC+JDOa9HPe^0#-OUA*OwZ?nwk|}*N=ppF+i<~m38^`l`1TDmxBrtMj(c~h}ukJc5 zp~jw}9gS@~2YsbuhCv<)nbA?l;5QDUCl;r0453+K-z1dj_@1m`RcEsehayWTcD60M zhVJ^&pwEoY6y&9}3O>-3%hWWT>gv}xCCu8G>5IVFu+di(;9~b>m~P&dxA}e{;O3qg z$sQC@5cfs@D#b7c11Tn5jaiW)a|flAmJnaRg|!JoP$DKy2e*_ymK^qqqU2;e9Kg#+ z!}A4y7WV6jfZL{srHZf=W<}+b+ZD05U^exx&DoFHoq7ec4)WHpL$z|~@b`P&T9Z_% z4ZG)RQ4Zih;&EMW>Ms zEGBH@Esgq8{71vjAO;`1InV-xNxCK23QD%pK~F8`5}CZUwY$}_Vj+jx17=Hd=yU=B zfdGMk!9shK)IBZN+1~1DYSc9>S65@RnvDYOa%!c#N-8Gsm*cXT3@RCdH_NeoI|?qr zazzDsxwYi7nvI+FZCyzOIKW}P5jiVY^!_r`C2~-K&ecz7?{0nP5mmK@sU}I_knjy+ z0m3dew}Kz!e$@F55wGNdcX+hpKy=M*aWM;rphnePi@cp*&kB+p*NkKWP&zOq*9m5P8qR+`KSA>zNQXR3Q2*OY zj<=fu9W;v7PvGdvqJY6`D^dgD{fNcY5wY{Xnt@@m4ZNJjiZXI+!#x zT4)uE@C?b6De3nw6S#Az%tu?Yse*pi-XF=yVS3k7EwigW#+Y0A!I)_iLA_XgZf7{^ zB~k6)xHOl+yuHMpLVtKrk2fvV%uamJO2t@dz0z+607m|7tB>Ap*Ta77jV~BN11wCJ zEvq9XGJ&e@J^x;B>pY|fX_Ar-I}-q(>9`B|E0I(rSo4(A?&l2JoSoC^Ru8WfzRX>V zJg*z=1Z7hG`m$3`_)S{Wq*)rs1K4~-n%?3Bqd&SGJ_Uaa4ir`Y8@Ha zWK^V))%Hx7l8Rf=cU_64o#2`8PFC#XFd0Jj&Ir)>@PySq3$)ae2r212jS z!#b{&LSEFZ@Pu)6m)t`)hx{qoe?!Il@NRh2#h(xf*> z>hJ(D!pmip=W!o#KZFu%zKps3;K`>5Z`iR4RN`y2G!k@d8uJj2jm=Dgs>Kv>ag|AF z;pljusr_SjFU7QNr1@W+50-I^=EHnTE{o&tz2bPhg4U^E#)v_?o!$qKCYP*Xy@xOq z>B?8;_$J>WhAl?qA?};qJoYr*ctgpl8|1lGnZ6FZ8-^YtxdgHAb*S0jR!uO+5l5Bz;>^wW;!fEe^}DeN}JLD*&9iwl*2){{)Bpr8?YayE#m zl3<>A0sL1tO1Xg1tf8LHJeYwa4`8N0sb;Ogq851b>U3~E>cfDx5fNhUPdkGB!-mpw z4M&u++$>b`2KUJ=;bq5@=miAJ;^MYi%&`LKwLNPzv(EGweT=C6@=BqONohPObx-dt zE8UQ6*kPR%HP|R_mF^==h3+Y-) z>+ycVvUtLS4=`AueY14GRW!W$d}xjnoIiO!9z3%a?FQk#x+aZzy~3He;7mNr4`NIE zg0n8((}mG^jz5gncxFo9rV~;NiKKRy5#}7#OT>#_ER&nf&j&w+nza<(prp9o=LfoI zwOTX@N84d?SgkQ)?@5Qm3~Ox=V%&Q#s30eq#W~tiBYDc*qEXuR&&J(iJv-|FdM>>8 zE>>dW4CZ!sEK;&K;$v3ky@`b%Yd8y|{>V}pJ}+rhi_^y!Z<@)A+T5&joH^c{>%2ng zzu^?)$onP9ymphfO%?6+>NUdjdMpZ0JfH%{tedj)XfaKwI#bQH)FMk|jU@&%KTsXS z;RN`0ddJVpLVM={yVt68VJAA)6QUNl^!dw!yV>6?|K80}vaoTrzK)bL1}*}9>>PBg zMD2K^(}kLhxHh-W?7tV|VHnu=L2E9l$oXt~0s}dm95RwVL+zL^S>A$pWl4 zB}neCJbm?@J^JyA8Z)DEyA`vkWx92HOX$L+<5~Z;j@kKed@Z3zZ`tstNEK zW-@gj^Iwm&n7pLyUv$bSKS!l!`NRA!3BQKOQtpx%(#cVVPgCD-`SF*4KJWTLnWgpItr8&wMHMKTl#}YOuHPqMGE!9SYR-=#z`Ai0tRF1>I*`n)M=UGSNc|$($ zR?lOqLcI6CuTx68rjg~|tW`U@C-b|m-RFC17Dvl}UexgbXY%OGG}WgpN%~jM@hQN3 z&i+&PQY6&Pjq$J_D;$NH%=^+9`9>fR@CfA>kJjDFT~xA&)4eK;jn{AN!p49`bo{BY z0nmuMGcvI;uzn4nZ7eYBZ0B{&F-maJ)S{zjgJ$E)IyEAcH8Pi`O<)-@@p~1U-i6!O z&+SNf1x!lR2Wmu~49$6R7ObF`nN6PTgZwM4=TkXZ=?cS4jh$p&lKFkFt8Qw{HQtKu zWKo>pE5x34S>4`>$FFjAAB0bIOVTqaB?+QgPK61u3Shush7^^-L88T>QxAk9N5zot zcnUin&ZGOjs4jJ*5;89!j_lM?lEdOK6(kZ)UNA@!a}Gt1{#Gfof%RgYR7}js%%&68 zz86F=J*2`ae)nW(Qifw0cN?PAYOuT^7;f1_mOEEu%N|xq*IQ^sl0gF>|q!8nL zfuhEp?{g%#XLvn@lFb%Ayh761+xO(6vek}*M3*~?>t8Z<)=P-T^J_(o9PZl0cWz4{ zbrt=?K-aR{RR!Qk;|sigG)A|CI=F(=(>>&ba^igHey8XIhzDf7BzgL%=mwaLvfK1svtN1J2fxJrEKhK` z?28;PXnsESzr~_Ij9d#38;hEc0i)FIeh7k!DyE{Xx=r~L1}w#Ygk_!h-v*r zx9Gfe)1B~Ixv8f}?3=0E`rD*=yY-%X<$d2aoGBz#Zc8c3bgalm%RbzBSs_iaX^BG> zyizG{c%|ELw};$>1AY@$m0?{49RZ?f^OGQF4?!6%SE<$n=E4)*pxqL zef~1q@euURMI8WePN_)V{I=oP8{v7ssI|Z=Qo(gE1BB zjG{>>?2!DlWon)A^sw2R>oSkS62fvf=e)X(XZytK%Q8g91w<)RL|WV!h^DdotX1k^ z^IhA~zzBRjkC(WB{XJf<0!A9PsB$;htF_H?lT3NoS1(+j8Q>@^XW}<3mf2mFvCavn zI}0hTmf+X#o*w6;y{~ujfe+qho7Qx$bgfZg>aj*-cC~az+)_Sx^?WjnlI&5*a_A&p z$d8NJO{59l;8M*45sH(IM|;RWe9sUnH$Z$Hp7J`Z*tC#AgJSZQG!f};s!j8Tw6yfS zyZddih2~J$8C~m{f~N;@%|+0s*wM=4HuMx+&4vrG7w+;=rs>ts><;_k{o{VUYzFkV z(xsS$SZZ4K-hKe5l{zz@S9$+S!P`O|J)hAor78nfxHqh2i9LV1bQ&LnACC8X0 z!51WnAeFojnu!b(AfOVrB+y_`QizP_XEg)cVz)>JD$_)P5HoLA)gOlYnh}bkh4Y!2 z7tijXi!2c>gCFC69{}rpP0v#pEqS1gb{>^7(-!FvKa8u@%M#|}?5b&+n(N7UQmJfPWR#=s!RX4uLT7z% zjZgo|jNbq(6pMrKoXD0P$V-#QrGaXdx_Qi}N$0+oolzGd>kg z8Dl}^2%GvC-L5Sa5~n(X2UeqnO)GaaFv8YmB|V0%bPGqA6-J2Vn6e65)FO!oMx7J^ zAN{Z1PP@PrO~p#M-8@vS)in#?=_XoUVW>{QG?FzfBkD``gMM#3(W1k)ZBOi$dP)_r zY0MRv?>w$~`oo2eP{bxY;-m(j;(X?NMoheLmz)spb%x9*ENdk%`W!uf#}Iw?|3JbY z$t|#VaS&5Iz{Z-V)s5tg6X<{i;Ot!{9aM0D9KFm~4X*;Q)R&XDqaOl3dbwEpcL?6= z%REi1kcOtymV#BpSV|DZy1>D{3vX1EHT=rz$@PYxJPHycW=9mq!h9TCznJguQ*40< zW-coZpC$-rSn0}133u?(zB+p*kB{UA3KX+D$o_f;VH4Yu^PJC$r0EbNCQE_yu%ZfJ zV7p>kZZ+q%zH!YbV;R)MX$0Nh$sX_5C+U)XgX1HS&QJ&ocspZj8y&)3 zrpj|F^`DZgA9hhs6`2O2Tq&Q;&t4o>#^n4+xh1mZ|LWaxyo1nXsLJnh5(xP$MZ3fo zM}DT)!m6bcFM`JBhr!h#;XaiBi}f!i!Q%2v`@<&Xan-tm_YH3cYWWb2IpX(V%fVEK zu5jSc6yuY|`tX&=Mte>o9;Xf@8k!1GP5>49Mmh-SjO|7jt)KPtB;$;5o4i+VG`Ejb znHu|;P4k@_W39d!)E{}x_b0BnLs~jS+tGO&PKQ8ebYm6p#KZV=6h%nFDQl|8N{v^% zKvZ#r(*a*zsh=W7GXC9LXg=Wtao8*QN>gD5xf%^+i~0J9O>8q^meKY0R1b3#HsZ+Ku)NvqqSKIRS2xR*SbcLpq;@@(X<5@TW7AEuU| zo^bG(7d!PSL((OWVAGdGS8b7>zA+U==RLL@^R*g~VPG+fcxdrhbzbb_II&2mpcpn} zPUjN4PL^R-aT<$e{G&TH9L?R_`VwV>kD}}d+-)yKz{1Kk+FZr|@#J8BICrfe9yWQo zT+etc$L^@o=ZUoCjxa9K(3RZ+Cb>>==3CdvF&!eXNZ8pQZKiKZS94Li?6lrz43jbt zW2qQt#y4gZ;(+3>xzSsmp zUkYlJt;wylxyCJFT}Xkn4bStS^yJ<0?pfDo2arPcLwzHR@EqtX!(-o(e#qDQ@HnR6 z&V87EJ`0{omX{Ra-Wlw!B$*BAJeQJnQrlTp97so(5R7ASAZ-jV2cDw@ z`i0<-p?TLe&w&(v7o+&g(*gVynu{+BwbM^Vai`BGd=3sRtai0){?Lf#fkc(`Q@jx5 z8qFC(y+3|B@m}Y&fdnFPP%k4#!g0LIGBu%ix#qcW3OuHB0g93(*H_Ndb;si7!e3#%8-S-GZ>%}Hx3%kh5k`gXmX=9AI7lr-7Rw%m^!8OuE( zEM!`WFd5&pu!lbhL90nP<6yn}=rMt|s12Ruw;v9WRL~!fO6(b&_2#u9R`@99lW#Zc z$7Mw2M5Nybqv!*$eYTNMI6BGwh7HU_G$roAylTLQI6QD@ET`&`9DY)U_|q2&V(AEx zu?3y|;Yz?rhAN}@{8NeAwHiL{+|I7IWbCZKVjc7%;7x{#i-ZtJkSO#;KUrGsTZLYw zlFI(A=(1n}{pvawS=x1Zd1Q zu-@OEm6&{-6=~;I5^vkt$BHg?YL-quB5{aa>8@dgOEOc7lDJ|$ei~e8fn?i~p!H*g zmcXcqhjYJ|!N$<;I8A17Psv!_`37YZs(z1}c(mxJtk-q8PjdJH9jk3Q@@7#YSht$g zs6a43!ZZ#RP&rnR5@=Yj6S7&_i0KJ#39?`G?YU92ZjYq4f&7UKF2zs&l)f3Uo;Fl} zI3us=@|xgyjOKn-+R4i|WSfr)0^G=|kEk~!QNXxoc`E%ajyolh=M!Shn@!3_5NZjr zx`nZ+fwHZVR=z6I_^z+zsFalc>GS!h)RYg8%!VMT-eLI`gw*i*V|Yhm>?lD*U@&Id zT_5rJ!L6iqMdKD#pOF}L-L6WBR&gi`$(aOK-{}xvCJZ1x#4$b4Nb&1n>dGtuS{6>g zX&2ofCE_v1UI|J-8CXw1$NKp*{_4&3ytfsD3Sq1(ly5TMRStNl*N|5mt=&9=$}w~E z-AxW=S6r)T9dMYE2OBqn=san1=^)#hKi^TtTU75bVMw8yjay(kos?b5f)eQX`OXm2 z-kuKp4iEQKjLoBLf?u_)Ekt;`l6PLGA4H-RAL_kP6Gqc#~aVuhR= zQz+o!7|YY(ZjPxuI23UU9CQMSF#tMvwMUGCUdQ6#Vq>6MJ?89cm?+783^;Z%%2V#|-l80ewgRc9sGVfnH zKQDbbfc&#}A&aTs?U?*4!VhZYqe%9p+kRc8{AQLVy#gtbPyC5cWR|sF77rhv`U+yP zWu+P9V_n*y=hIl3^PM&GAYLhwcBG32mMOEOwJGy>S1G?d%;xt+n0TEEF^{Mxg2AEH z=Ps4FnSF6wWK-7aSYo>rVDMx;Dixd-Cl$huLP=D1gL-PHd^AbTU$=*D z=MLh&QE|^Pqt3>+%e48=>uEn{s2qI0Zj!gND|+kY*hlf>v=H|rUQZqii7=KN>Ynyu z$7CcT+jdze5$(-!UeMrFY7!CGGux)Vt;;;l*6|`jCtqCysUlLb)_hf zy}b+>G)nl7*0;olosXEE&^WaIqGEUL&05d)<+8`*d_8?rw(G1+qTr#B&cLIM(BbsL zQBO<2;glbiJAekoDCdfuFYHu$A^cNe~-3j6jlO1;M zAfUa;&kAf0ML^PfWa4W1vL)}EK6(ndI*Qph%PMC^4?)!}>e=>U-~}<$`Q1!)BNQ&4 z_iWtf%9Boc)7G>dOUA#bK2F@;Lpke2*y~447>t*^ahi^qlbp+GnaId!Q6?Hs)bYBa zpLH_Sl4JR2UjB}oBVhyfzslAq+ zXmCK5H}#}-1ZCJ=R+ZOU>W4lERb08`Qy+qQV`SSk3-$8$cPu>-k-A7R?yr9zNN=J( z`gWqBin_n)s!C}xMKft`TlTSl_^4jkd@rUinn1ztJBr8caz3nNW9j5qJW>HWgqkUe zAP`db8gSu$-lTgcI^6zZl;nf1tGbV2kX%n{@E5vc?8u1n`O1^x_lm?<$P`+s0kIw^ z$QB)P5vs%%REC8lYe{z0BMce~818G`G;L{iH39m$$oYC3ee@K~!|I@AfINBB9Q&fi zOVg=(OM#HAd_LF15PQ+)XPfZLesz53$O3?gLuFS8@zjL>f(XxZ-xd#Av;v45-|kVL0*|yL+{} zaL%2BBg0q|SDlMH4!};-gCAd5`^DkL#~ zu+qTfn2zAIagr%mxrfPfWZ#FBGQ0k=kMJ2O2gjnk|Ii}}x;g+^C6;sYn9j69KcX6U z8i>z~%Y&0W)t&H1a)qB>U_`f?xXN;(nrf_c$FJVrZ&ybRdaoi%M|IvYoOgoN^XaE} z*LfqmCd!yeB-@6@$89TU3~6V+PKVr}k@FVJHB;>Nn`?@)Z7{d9pD6qZMh!1%tY1OD z6>i?0NtTj%)$=v4Y{sT{z)|;HkEW&=Cu~R#6TqyaNmCkIL^?OOSy5`cWFbtw3)auQ zziuq|{_|1uAjX=I>Ej+F>zJwO(>LCa?{7n&>^T~8ayN8NBP|ThEd9*=Hum+;9?iCU ze!5-u7VztDFH1?)_=G91|J}AikTMxIBSazi+sZ^jWt(g<_^RWrT<8^9VVlt@5TyCl znqdOHOruA11r!g&~4hy$Wr|0zyq*H`WD(>$0RtF+a(|PR!B`ICo?w#CUZJ ztIC*=zkpvgJ-@H@s?N@3e}23?-+N#1CQvEav$kGy&#AC{rFo=s!h0ReuphHN`IB(f zlg!!k;4b!Y&@E|41fJnxMo%lM-sca4^>&wC&`)@A-gn=uIJYWYm)9}FF}qza8 z`1z~b)v}p1X8IP28Nr3$njiD(uAyb_J7b@!On=Lt*mv#qJmH7Qg)M>R9O3>ah|v1K zDvRr>%Uqkzdh*4}pkn)n2V#}3e?BEPmGd%a3vmmGWn6GAv8Is|%~PJb&dm5~Y5Uit zG&@gPh!xEF*JPV)W2LB{;~K*%@~f7|nx9M1e>~-IDlK%7Cr<2U7Ed;h>&C~4O5W4E z`&l(lpgT)BuI}vCtNCo4sGI=%rq5h1C4UD6%oY14VATr&VZXr<=*jFFxQn~n&2kYA zLX$34cg=bGz+)9%k#N;n+JV2e7$+(GQt#gUJ>O$4=hA{%c?+dj>+f8>8PqptG49vP zagTQAbmIH`iP410|KHthIqX>bk$?M}imG0yPEx!YiCu*RvMW_z{O+lk;z&_SBmbbl z*S0SwGf=@)=Jdt2YU4Cweoiwy|L9oMI__-;GLg5z|_%~osb-Ef8C z^C%ZIm+f=ECdsq?=;7^pIiHRf5Y?y$vzFC}f@XPGBi!_4&sK9f9`?KKrWXTV!9>aw zBt~Sx160-9emX3NFR1eo^6fU&o4rSH-Zz5f@Bz+b3CWK&#r_d@{30mqw(TRYl&hmW zSQdo>RH8_Bu)rS==@k&{=8Y;*gzDq@SU|dX)0ks#o9cOtuM{cxY3U>xwQ%L<=9`$V zu~}~UDz$WQb4RK0k*sF{R36?!+Y01hPY-e-Iu^FRprpjLLoulwrU)3J1jWH#9su{@ zamZdm46#cNYEZyumbY>6m~b`x0{iR2T|bouhhos<@UVm7D@nZwOEx>jfSa^=tz0g{ z;$t<}AZ?lTVdLBDSo;sH5TF2S}D z&{6xDA5x@hW!E<}yorZaA-MG#q4!WVGiS%}RuFmWOA#NO;#DiXgIYljYZ>SD_5dkt z67ez)mZAr7zZDN)9c#WMgRImvv>NqFsaVJaE=&L`r%GLN$Mv`vmcfc@JTiaz&WFkj zSw?mOwh3;FCSigqT;^NujbwvcsfbU;wo;hBC+oP@skLM-ky=NKXD1Z2&s6+=V<}%$ zSNb^9J)Ju$mT&_R)&mD0mv)LH+98bn!F|1toQ&UJaDfZ0xK!X(%a~6YfzX~2;vJV9 z!$UP|68hve5HV%PfJmefNcqDKcuD%6u_g!Q2vwsPrYKf_mNX(vzzIg016Keu4)cLV#5C#n`HO6yfi2gF$#^WNKQ*}@)xlM&@HSi9v(4eW zp)GUP?d^KCm>a=$%+qJG5qT*R7UB+$`E4~y7(pU@R3a_p7ww*aG%5Bwk3CzI#*Ad0 zc}1fli{fmd8Q~#VRD)QKU9y%Ys+uB3Ovyu3VSRa(4mhJF-r{tkL2T_#T?uNR&1N{H z@+O1ABQW6aNbT`uDs7O2rAUiX$RfH*S6aU%j3&cA8U&YT@eY2{*kq4%?c{%h!0kykpSJTeLXYd?9ef+o`_q$DPgV=RES0J|( zVBvvpvh`Z4-IY#b;u{&L>3i4y@-e-&si@>vf!$0=6Mb(kph@&I=c*kY8YHuGuOPqT zrp*m9TmH=07^mwW2LM&Y!=>|XY{s>DU-^{XZ%;=i7Km|G1-f-Ylzw2tJ#R&H2&xm8 z&lR@WS{q^hyj9s_&W(MsPQ%@9k?18P*(_7cq3}V65X$?yeW`O{pQ5Z`kVYC5g_yvl zKwl%achaNIB2rmq7!>zhB^B_;V0y41%de2_&XOqSBt8^kVfq2Ydr^VgqCmEiYj@}* zo5*_R%xxCjy%F`j*x*1q}OR%5H4IxSd`D~fE3AEe1gUAg&JcoOjs0dpp?TO z@erB$cS3y^i>L4QLWA}Qk$$;NU_n=QK*8{Rn81eM_c7(~$5}uXD%hYJrAwP+!OX!*JvU$+H zMi15zx#N4$?KCCuN7GkT@;=n|AUY4fT1Sk{1>^yUlFEVw)VVS^Y3sh8Q)m5NAZ+%! z26j5#ZJ1sH%S8}x!H34M*xZH={Af6k?Y8=FtF*}Jo2%vAXp@UJ0BlzqoQg5x*Eyei z+NgKvoijNIVI(^CJFeUF$N0E=ARb+IOHAIunDNjqCWpymYi{%0T*xcTnwU<`@d`r_ zGE`aWp}m$%++ylM&BlI(~hw{eyyE!qS1bHriFK`!RpI<2VJD*+A$;cQTSaTM2|j@bWn`m-?+2gJm+NZ-IXOp_j98C46o;C`tT{q zXQaF`@69Zyg1&h%=8nI^8|T3BSyu!kRh$#%4r2?!9d>~F=`@KX4yH7nLrXRrUNNRELuPnr ztRWBx?);`WxN@SA6qyo}jj%j-cerCyw1=xN2lbt?XFw!;@h0Z!D2RXs8k#*lpd&u{ zNd=jLZ^dm_zrgb6FnU|W@EM7-T>iKI9c?jEk-0uWsIVWXvy2l4TZ(*Zv*Xsou~m36GaRp(~jRccyYs+biPO9n00 zC3|~D2j)%ra+-_)<7704zO)j&{jhS!Rvq@}Lh8FRx7+=UXg>vL*SYq| z?^U)@1n3fTWHw2PVU6&JlPk&X=Xm`L!hVw&J|*c)4>a5=Z8mpqxo|2<<^JQ9n2L1` z2~KgiIORo$q_Wp>l%laQ%OQ_twdJg^7bN4FDdYV8QGFP9%2-h&QLFFUQ7gxmIV#_+ zTSw~Q>C71to?QzoNZr~pR*ykl*#co<4Wa|}nLcE7$oT_&3R#`I=|Z$ieBed0;1bCz z#tw~3HlkYzz4hj0WI-{#h&!%}Q%2Zi?e3dU=T)6jC3ZmftDGReM& zfjTAFNp7Y2#Eiai)hF_}f9D{I4u9Aaau(<@^sMU>WyrJ|M;|A?(WEC$3J=o1ZR8}Z zz@h6cF8qb#x6^GOF^M9!xX0pz=&0I^@r70MNAN5*yr_qypbEWvHQE)qMyqIBF$Sik z(0tXXWK?HzZ(84{xjD~j^LRk`i{oiIC-CyY!#&eA0lUQh&1@-NyTUUP7ej&0+Ddr@ zw1mQ6%yD3dhhB<%2|ezSd1y9#{7!K?Gs`i2K{OuBbF`f%|MRynB;ofM3=+wq>`}wg zRVLm4_DzvmF>9|^PM8dn|N31RlCt6DN|L#l=l-}C;7QWPB(m7uJPDI}8utjDgMT@K zbu24#C4EiiS^F$`+LLvf9dq+lQ{tSk2qwYJUZ^?{9{$yqK8Y zoAaP6T#e0Gkzq~pxDwA}(m7GQq%pKsh4muPn6Q@=HLGFeSR^j*qw?be54>O!Y}qVh ze(gl9JjC8Y$;n$kLvryNBNER&G7fX>|FE$`tpBM00ck)=J0=#=U3~0QFJ?iPyD5H4)Dbf zPyO=2;Vb{M|8)id4S)h50RKiZeSmPqukqKbaA*BvdZvATVCQ%2KSL&r7b+)06m=1m z3(D#DoX;$Fy_D|pV?sSY#UykIEs)$Ku?+|Hl9>mF#eP|qwG_| ztut{vTnA}SeZ0fyg!=?+Lbr^FQ(3}G=VY<5P_$?1aT?7$etIHMbnf7b^fGS7tPd?D z>Mevd>po2i9nmlNrxWKYK1UFkQ0_yXw~uD%g*CzMN5O#8p|YG;=Jw_=!>BT``4>`e zN^sAV$@nfLw!?5n@tuvIP@K_t;$(OuKnkW43Mg6cEixB;4d^i^Vrdg6NbR zV~9WezU+1dgobFQcea7Z${A{Wn(dA!r&q|rOm?RtLgQKFw;QE{CUcUbYnF6TUTj;f z=PA>iJ3mS4cBCdt=ZoQHHr|q!_4;>ZpL1K?*!gIoq3#Or0kyqV9mB6QBOWB{j|SP0 zi4KE81&`A*Of$h4Uu;m}7RR_qlf%I}Z+h@h2fvhE%ZXF!A_k`DGcK+{ zx^;%pB9HKi$EC`)FF47L!TdCzLqbODxUq)s2qUc`(P7wEHkyX6H<4k{=*#;Z-9L;t zk(6uFxz30z`Rd4DPx&+$okAnF!r%+db6vj1B*&s5Yz|0Tk2>lkgqcoMu@T#*tW2<- zpc3CbT$-1Z9pr?sQ0Me7oXIooT;d3_nPOwgOpl`J98;!2G(Bjk2~aV469~%O9Cs__ zZo{=O|Iic2^e+*1jb2_IsSHpJDHV;#$mOK;Mz3Q-g+MS&5+!M>qJlPgH`8_^El3W(!;a}Gh42r};h53Qm zx#o*xD_&_z)F?NKG3QOk&Z2Fs44pfm{;-mLg%MTJ;03KS!<}-p5F^9zd9(gUo_Hzl zNSMK8F4-{CXr{&TOex3p`@xne-3oV9Bj0B@gUqWcH&$kiw8mlc{v}{5VWZ3(1QZRs z&pZ4cLvHAgGI^Tco#1@Lzqc*N{TM4h$%k`BteqZ-bAh##DIK&e2bQcbj!+@V_ZL^h z^VF|BooKOECpSS+m-VQSst(WeTseFOn&K`H)28A3R|EXp#z--d^ER_=b#!gzh6AdM z`n?b*LR|4yG1RMLp=(z|xr?~Cu5FW`okWvxPE6T?-`T_hJDF}xrWW|G2so3@r~Pb< z`+eQ6BJJs4drId(=Wuul4q7~(KqEZ$ZVHQnq}pVKku4Yr7+oymW~^J6KS44KXT!vo zj~#x$&)#N>UzRk?MF{^UAE80}GX3w`*QAm3qsWr6iIbfrEp1}h~TZR;fy z57QV+Hm|Z6Y&n_GMR8r{h~;GW%j+L&I%z?rPU@4#yyv=%o#VNaQWPRumKX*RWNrx& zWQAn=RGBL{|?c-bO^3AI8wz2HK9jNCLp8(yOP#T|z zo+a;~b=d&k;Sk6|i~Fds&QC`02^zW4YZ(O`MG4=7_lOc+2tQJbOg`^q3<$@l8NrJX zUJJhifcISZp6HJMz;6KY8W$_u`J1^#11b@^AesD(X)W zszm`om-csz`#GSkM5hWE@%w0t=w+Z)AsCzlO)Dcbj$Q&RwC)f#|G!C^Zyqc_`kUjb z&A5N|_L{A~?V0yx1{jU^+h6#p&qfxE6i5w2qDev*|OV*NHlZKy?R(iC>b8YG08EA=iM1PzOo+x;8_4FGqKgT&f0?9L{ zXc4|1PsO#DZ`fmU=03zd=~fF}?vP!!XWHRD5H#uf<2hVoiJKh0W#0}S6;Ej%X<_$I zRp!qVzlgsJxxUxG> zEsE=<-H~dMms}J%YuMk+39@A#xC<}?0vm@Pli!&mr0-=Byzo_aysZTPZuU=oo>B+@ z=ho$7rI9)Jjxb`AsIMg&aIxYDls)XrTtdV zn+~^oX`_{vZA4pOg1Gp?IFRCFMM#d`L5!p-8h>9|VJeza> z)TbBX_C0Egg%0h=W9GTFwPzn)yfikZFz&Tv9z*(??M$ipG>UuJ=;7=YoQ-_2yqKU` z?VWKAR>~rEw8z%XF$;t-%A;ch8ht#WajlZ#!ua363AcCi>W(w1X>e-zqt*Ld=jWMr zTn|8v|hM#@$6aQuUq0lMRgOg8&r-?gBF<-1Q za(IpuT5{IvO=EXg+w||PSVP;;$*8-$GokuWC>?GJjs@(LiSWPf{FCu`AE)YY8BL!a zd`4Cv1Ht9AD;$sM2pe`>c(S7p3+j(Adfdf1RK@?v8Khw1$E3yn>*Tb1;>7zT&x{+= zB)jc@_a%iA7s&S8s#F{|gTN6h?s!6gPpDLeWtkQvDmLex5{vP}CjsJw@hqbv?)5x0 zNJC2%s#1+Ss^e3mxCRUw(Puadzm&9$%k~FNQArsFN2sW(sUt70hQ?rdwpjGSJqvBJ zjxNf!pT&mQVo0!kD?vg=K}AEyz{JAF!NtQTAS5CtAth6(ikyOyikgO&j-G*$>6n9s zm5p7EQ+Dop4IG?Y8oB$uoE9Ff+O+G?sY|yW(b5cXBpQn+lBskio6Fza-rYYuK0Uv@ zzP%TUrE;ZOt2dg^WJ#OVyV&`1J=$`twXMCQv#YzOx37O-P_E-c?TMj?QkP+{0mPTU zh*_T(-$Y{(Ume&UjPdDs!d1C4M=bYLXp*Z?k!L?vlQH!d%Xs6QVyRpKAp6R04c>d4 zeQx9{7=+qS^dBos7E zI~smu9-Bvyc^WvhoZ%7hG-;_ZZUJ6Ce#lTz;xG72ghdWak_v9P-bTs(XNLLy=kQZkjQ$ji$4Td)Gi zUmNlFq&0GD(yWC?t2XUAbn4>$BKNm9Rvh^EjU-W$WGPZ}T4~a&XI+pfOST-j@^IuU zP^ic)x7~5q0gP1VPv1@4t(g}&12B#NfC&Xa0ssI20000;?52no{LO4J#AIg93r-0V zM^TAf6GgpngeSghd1DsRm zl8G+edX)PcK%lVvi2r#&p)pt--p1C>-oeqy*~Qh(oj@d!DO4Jr!DO*HTpnK_6p1BL znOvb%sWn=i-e5GDEmor}##q_dIXJnvd3gEw1q6j4!Xlzjn3%YPq?B=KI0A`6V`Q+h zI6Q$!B2%aUp^OX9mr5H8=x_WV5Ew|2CPS7Sc?uLMQKmu_fP)Amijs<&hL(<=fssi+ z@hn2DFX2(F{V^fF3FnKQ{LMBp@Miivd4$Lz?VY)J%o9M5!&w>68Blu<~slgQP6rMwjnLsh*pe0 zqz+y+SfXp*D5P??^0csU}xgB zIt5?X3qF;#xTn#tFnGPe`SW&6N>h!nh}uHn|EB#yugG zHa1r!BBa`_UJU?ZLK*jjRNB~FoiL$NX=8JJ01+mXdBWIS10W_;XPN*BW!y`&gnB~i zOq&Vc!5HX5u$S{%C;-BQGVTefw6VD}gi8W|2ouV~-igb#VSO(n z-d^O-J2=*w!g!!=gXveo@#iMp+r?U#dwqTdD^JF2t1>R`dF_(;m^HA~Vb6p1RK~># z^Xk$_zP`n7WdAQM!Q(x`at$9V0Nf$K8X+RYNN|r7&}Ack1k$p)S&j%r#js3)u*D90 z9Ne+5Mg=I(u3gT`EXv2Dfi|@)7mP`I>IdEGwFJGy`1&L^pqML0$qgiQ_bcbS7^s|= zL)Yw_GeJJjIfLfB(VS~=E|1K!fW$e}Wk!n{?NHKHbJawD)YM){CF2hwok1TN7z}v% zOmsRPHVc$}6^=IydMK|_xK5w{R}VM@p?{3&@xyD>@DZTcfGzj)U0|wWtOop~zV@MtAVl9t!sh#`nw<#qQx8Q(||I349pK4n6 zaiD$k_+EsZE@m(HX5?;;P&9BN$3k1ngi%jyd_@sOy4tdgj`=Gw4`n_?28Ak6p@5v4 z3)C;>Lj79xkffffBr^O+`32pjk6U^m&k>F?yO&HKJ%GGK4|r(At!7?8G0@sJtw6BNI#w zNmjZgs}%!i5Re4n)M|aBsl%v3D9AD3)B>r%LbTFm!L@`<16$ZhSsCa;d9+mrUo%&V z!FY(lQO|6XH00{5fN1W~L=UHFs!b0PxEK$5T9xJm!#T-wEIOGM;yZpZD&~waT+%W{ zn)VPu10Bee`!E`r@TE+Jc0Yy(XAd06F$qGKl^c@`-EPO5k)|RWh7o?1BzJ_O0XJe~ z=hy|Z>L1dU~A)h=omQ6s(KRDeSk;h+uK*=2UuXrxTmv4K$r?`Y;I|H08z9IRAegvakPqkC_i_CF{r|uJ{PzN6I*up0 zY4MCJ$-2lDV2-~h^FDZDINW3enO6na-y{M9fpL*{6p3akn`;9^xeh>t31wUgrH$RC zv)uqDlyOf;rH#$?03uANC-j&!xa(On-MGSQLJAQklyOf;rH#$C03u8%OYh=0~ zTF_w7nHFIdZ&!L;>P95uwKj1(@Ggw*0_^^tyWGY)SSeQai;r(R&$Qn5_B?^^zbYnL47L8^KZg2UEa(9M DnuPx& literal 0 HcmV?d00001 diff --git a/docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff b/docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 0000000000000000000000000000000000000000..f815f63f99da80ad2be69e4021023ec2981eaea0 GIT binary patch literal 86288 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 z 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

msZ%O|+*Z+LS;;x4v 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%0AU9xwl*jMUcB+ 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 NDMp1hFB${m{{V&DCTjoy literal 0 HcmV?d00001 diff --git a/docs/build/html/_static/css/fonts/lato-bold-italic.woff2 b/docs/build/html/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..c4e3d804b57b625b16a36d767bfca6bbf63d414e GIT binary patch literal 193308 zcmbrmV~{1$wl!L|ZQHKuvh6P0?6Pg!wr$(C-DTT;)#rTo#uxG4zn76abMMH^Scx&m zm~*U^+eJ>42>=iP008J72LSPB4e4_M0Cd*~00g}9^XvaLVMm?7;LMtU=>b%bK=_$J zrl2E2K*jX%M;-_PvH_6*Z*wCD`T{|3^8ef76A-T=D!!K0uMUtyCfbipnb@-6~>&vo<=5v&El{-By6>L{OV6 zw||(fG9&(2G32VVLaL}&V;soRBk|UGrXV;Q@4hqz++ES86zcsi!$pOBmaPXk>}RS> z$(yRVKUiZ@Ywu+rI2x8d%2-|=3USQcE(0I-vC}|TFL1SG zh8RjT1O)~p%^H&4y;e*I%RH_~fq7)k{-oMK>?y}Rm=5s!QOvPUm?bA5TLMuGSw19L z0tF}LLlNg;9wnO0(2yrq!)YYERts0XN!@9!vuKYy)C|mA<=Wu^_MigiFKG3d{KCh$ zd7O0Y0yjNxpo17;Xc+rhK?{LuWUB}!yT;a)1JbTC+td2P@$?L-)R_Pn%|6fZ%1Pn( z_#Mhg6$K(uy7Ms_-7GnU&fwQZ6@k$*B*j9qC^{Rh7H@_r>IM{vXXidJ^ym$8dZW1XKQ(OAR|H(~DV#0HtO@y|>qAhz zZ$+LQmpWJF_8a)hYbf;x`QFZqcV$qNL83-at%*!$Q5v`uqLLl4dmt6;Qp`P3BV#W5 z096uniju@dI1C%5hTbrjBDj?3)Qa`uQEwczH3bFLzoDK2-Um7rQzvs_+)e=g$QX#A zt^tSamwn_0=${}smMRN;_EKQgboTl=7gDm)7SmK&sSAbFC4KVqhlii<_Oepct%_XI zIoh#P(aSyUg*5n`gu2E%-)SWZg##grz>21|6SHGhBXy4F`lSrmN9C*hnc}Jq10_Q& zv$7pgpmGZ7o7-D)A4!FcJ6gcd%5CIG6dU4Io~wHo86y_yW*r5vyj8H|V!bI}e&Iwo zKR}~)(awps%)6*HqQ+&k-@aA2GmVnWVxUKrbk*57s?I}@iII=H?l6(+3nRbHuEc%J z`znQ|taoIRmq*i1+A*peKsy(@*y$fq1A}=)C^f{ zA6*wLgh~pJ07pNFgfzpbQnGco4Q4GL^edQC1Dg>x=lq?;5is0O7fk}hIdSplweyTY zg@ANudQIdQ4uw~hH!2NM%567J3Az%PRUCIbHQS{-{I@IMRKglt%e!rH^=S~&5tcT~ zfZCx{=c*n{XCNBpA(kVfa)VS%tgiG_KRsKwQg?3v-4tV+^j{Y5HezTHT=5hR$NI{r z)G@%;U>D~zs36rnYW0#&>FV}$(9UO2BV1i;CKvy4K8X*21WPlXCYIU&TnphSSAQEc z`@ieJATZ8)+v`{sO_TGYxhvWhs=7U^J7s-MbFUR=z)<#k?g1m6S&Q961zLP5G!99e zIC)R=7;=gNq)Q8%*ae;;ej!J(`9$Rcl4vdd3)VpUp0?|xSijMntCw=wrE7F>>8$uy zD)$t0_Cu|Q!rjyVbgm78(k-ns(ml!4QsLDJ9<5^fpVayw4UD8GA37)C4;~6`r%n`lhr}*l!ZQPk( z@?v-pv1w%6vdEknx?`Srtz=ptlDGRzQbZ1OokXwTCD+{rJj0+ybSi(BHm*aIbLCJd zqxEKSdO3W4cu%Dt^xObd0OW0v=Nom9f2h=subU9}XQ*aP(!#Ojg|4N~pdfX>tMp9T zz1MHtP>rC7nwqFaG_8XZK6BZl+EmJ%+$tV<82-uUgh)ej34TVrvMftM5>P1!d9f2v z6CA40!Wo7#NGQ95Wu@L<%+q}_W3-btjirP1>Ydl;PuDT+-ac|?5RdgS+Tl{=xC(Yn zg7XqiDnIVDfB2C+T3JHdHf(NVHQpe4mhOO4;<;i~yy|(-=<{evX#9EnBhPs}744n2 zszj6bkYY~10tVZvoS^D>fSlHWoz&}j?M#EyBe`AcLU1^K!` zaX8nF>0IV%3B|TUFpDL(B7tzDs12@W_h(n#l*=nDw~`a4<7U7XT{>L8AdN`TV`Wkbe61G?Y! zB8}K|Zp${C=P{eznK*&PJYZ9Ax8|@aRaLsW>xz*#8J#Oe`OukK3`8dX#3|>O2ElYi z(OLWi*c!|01Cc|CbD+X8Y7aV&==s?EyK0+I;_+3CPOjzbRH0fQ+dQqywmS{|CTA7L zYaiKobqHs{b#;0}*~cB3t9+Il@Y5|@s+CnJ`*ri8ny%|#!mkj>c0>z^^8UpB4DNj` z&kwPVZCk#tz}N2Uciwxi(jSDE-`)btdtXcZcHfx~p@a7)fB-@Z<5&LKBqKKv;(hn^ zCdc=l`JV&c4WN~R%H@|HCQej4!{?>y*)p=kKm`y$1bT@Oe-6;6IM@_S9W!D|gMl9m zv>iDbHgr>8)*{^uI^(74d1a&`RL$i3wapn;#M!cdx1OVpCRDP`$1`OrncmW96ILJj z+NO5v7VU&H1_v|_)pwGAyCLwcqsw(+N-iHNmx)1sh^Jcp_m7HzsgdXA*`nkVruZWI zInfhjB;}$_?a-NCZ2C5PKb@mByUKl#?fATr^Z2M!7DZ$V*2v-}r!A)DD}zH;hTl>r zzBJk0^b84gyJGaKXXO#2EBAF6bLp}XHs|yy#Vd`-Q{NfG;hiHb?xi2A4$jbXp}d|> za3eDhT#vD;trNbO`2_8IIC&f1WVgerC3RW|e3%1Yo*9G4`~KXtCs$>kb6bAnU#ggP z=AwR`ZmK0!w`{TU>qo~^h^MCO`WtUL=r$eMKUz##LJds2v$OiVT6XToTA0aI+5O!*cH!%5EYKY7%^WKUNN1 zUY61<6mX+VAumY2mB%O(3(-z>N55siZ0>wgzC%9b4!t3RUm*vEWS zx~abrUVk5IzP3#8DSj2)kxzVg1ib8v7wr&!^SvUz@{N59d{N##r^w|ha=K*jKO37trUp@^jhRp@GRRZ$1t zVf1RwhwPd30n!#8uO`!|qHku&Xz#q+&5llPm1am&P8lWNq_*AgWkUbvXB{`s=`uZ) z4z(KBs`=WNGy7Puw%}NddQT+eo5aQERV`xmUsQRAEKf-)Li;MBqLAf+V9h$E>3N_l zgz3jm#Xjm-cMUnLG-+Y-TdZd7Wsq@yKD!`fg~P$G5%#5v7OI`rh`UeuwWXOnGd(0E z#(V%cfU9gAfDgWJ@Xx2qsgGCs2LvQYlDT9b>N+BrLRpYp7>o@{;E3;>6?3wRu5Il& z3V95!JuTT~qb5T^Kx~p`k_ie;rtfcE{j*Elm*Vqp)hn;-`|#Cj2NfJ$g-Li&`fjPU zA;+RrR5NJJbs$>QBEROc5``?1f-w@q!>tn-RyKj zgLptg|9k|TX|VP<>-7CU-q|}xIUYNff+QLO3gdLb9vp`4NW>+rO$rgw_?O;F)%D#3 z$O0-ezOFCF@1IaUF4LW-Znyxoy&8oE(vhJcRPd2hG(8MGXLPAT!oN;g3-ZwxEuOBN zJ#-Nu!UUy21UV7~a^)#dpqwy4AjEE>*XVhEh-Tl?BGrNs~@_|DUQb%G5Ap9jbEuwLj z{;9mu&xl56Px|aA9*ZEHEFMFx=&s`?2qAaknoX4FI*%MpEmysN3PBi%AZSaY#gYAB zx4#auRU&0PM9Zp6GO z3+u;cDlK0CY)qdsZvWxX!!JR%P;53FfG`H1Rh@1(^u3b*ze4*s!sr~H!8k20T?`&(=b zE8S?B%bb^nnMSFf?-(0a4|F*Q>3H8v=y(s;KPhNoQz?-O85p+ocPP&Kt5Kq(1K+>R z>0p>`xL$AYL`Rrmb#*l~xjq(&p|78Yzf#bP_`GVxd#H5fTQ&50L<6!hw}|=kFhQ7X zume~Uq3-iEH6--Paq#8X^6}fsSUJ1$ePdN6KP^xoAEh4&kGOWAkO6ByRl8?>iJJ#t z0}LYEfg>tIBYES*l+JrPW&I_~%`G7$#DPOK+`-i~Bqhe7^%uL;I}fJ;HCYJ_o^3p_ zdr$QiNiKtZC}bTiK*#if@-U#KfH-{LCMO9PHVu(JHfDdQKulyGMr1gGKrMqAC@L^Y z0fVk|<*++2@Zt(R)VZ`XFKWL33vKlwq>brNB1|#?>1Qd2o-QbHJ`}mL0-ikFe5+%C zLqtABdcJvjG5ImT#*4&8P?=2Y++Ms)z!L$lULraQQ!T zRP>LQn6Y3*i7F)eZ_J;#NK4D9#P^%Dr0JnZ#M4A8Kz+MAE6QQ;=)?0-g06$D15(Aq zCw3Bzn@VZ;CvdzqrClix*`mtl9XL1@CEhS7JrItX z03SQ)uF>}Ua_eFi2{uIETh@c%?VLf|a)RSK|7ghBuNtxl7v{$DK1V_rSBo888OLP= zaRk>(IB`}H2*^NB?=Z80%}`-_swv`QL#uW4nlDT8hQXJR#?{ZVs6*LlmCnx9w>>QKwu>ifCs-$fweOIE-3zNn zLUX;~3#fGc*fremBScv6a=@9F4mMiiL34swXr2qYBAIEgg)7UZC0Mx40<-jdv+#WS z=l8(;OHV?}H7o)`iKG!#pku4%DH_u2g)40;m{|G5j5~N|WC)s2AV?b9&(#KJXidu% zJ$(bqf)35WCQ~FiAJ}AXtxzdxlu^K*+~6>#^N3!9Y@&?GS15@jK@5cec^L>0A%9%` z?*j_}&Ej9vX^QKH+%LJnPIG^Ts&4p{3gcR$e z&Gx-PLsDy%T0c=h-u-=WxX;l^d&lm`VKhj>&r=J!eHSVvN9kW&cDQqo2g(NtN-G>% z2E#TqZ34=p1_7PysL>bH2;`qjH|q?I?Q6NBRCN~QaP|KrBNe!#QYkkh6&8OQPeG7y zpJdhD-rFmGS(;k7zI?m=g1yTA@;K!8uUxx=8`xuaN zc@)3$M9jhr5r%+t9g8NiQF2^t-PMZ#zsXfK6Dx{mXB1?q&0{GYYb%pgt_zxqYRYSx zcLB~ropw65Q3Q3$096!=MA%123gP6mN6vktb#-LYy$li+{sql_Hbl7f-6iYc@vIzm zVYNL3$=m1Q+V%NlZ+aC9IH86CD0!Or9^kXD8%Bnd3FMVh*wI*(#Wd6P4GeDu42I$A zdaP#C65PwD6!vb)h&fy)aEkGSxO z%Uev`y?7k)$%~fzyay&e5Hh2KfvU}k0H@;?jf)oaXF+vgK4fi1$p@EC8#Gs8QQ);2)Ht;2 zBBh1P(x`p_{_zUiiB2v-3kf`9B%c zk1m-11ibQ3z$Xr)|9#elfuEa2!6K&o_?{^?R-L*2qE`>I#Cg`vkg0M1nnw?Xv$GXM zTEE=4SA_Tiv#DC(;s+WFb_D{*v9R^0CL0K4UZjzSc#&%|9yJ4I#$%3NfxjN8kx#q) zFst_FKvrf%$rUpN}m##es7w;TzAfs8{FenoG zC3n$m5z*}tH^e35OAx`uTn~_0^h)!Yx%Zg`4OzqsSmZ0_>yxueu9uWop1)FVQ~b=w zg8PDD*%AgP9nqybfu)a(<5<6#?t`{KouAw`po_JwOltrq}K z@`z_C6OAx6>ND`X()8AFNd&-mA)7JVZ$z=MIc3AuYt02atwKk(7N)JD4aq__+Fa;I zcpi6KL+-C=m%ZE&RxIb#Vw}YJY!&PP20?;0_l|757 zyDqAvt=5?kgAV*iE(#!8@3#}2NLM-xio~U@G@Fe&^*OnU8fh0&^(PCbwTkM0Z+~cR zQtq7UXSV-I&Z+FxPR!5p&k{>QO-a0nKt-=KB?Wz#vhyR$zig?SSghlo`QCmrxyIXL zu8yI34aBC_U5YVfEjtK2XgwfXIjH64c*dD34W`jF;JNwuuD?!NR=F@qC*?n);v+=O z1(J?bUOI<-U!k9Ay#MUV7UW%!EGltCB_@DFRF^kldw)Jwq~j@Z_MQgrf)Nj$U4_9~ z_a#yV^1Zp~dek^QA|w*&E&QcZ3C>7JbToar4gYP-RQKr)jDJHOZg zBl2`7^AH$B0Kq6OnXH^+qB%WjYaq2x9@~VzD#Oq!f^-3-q^Y)?)-9e|su*Tq84vOX z-ZAWyHx;EX){65ir*WLoQk8QwYz~+8<$6PP%K0EmU;TU{8Df90YbHLfPvvo~Tq@PP znYd&< zrDU^&WHaU34}Imr_$Nl>8@2dXXe6J1G=C;cJpRtlq;jn18h*@Fm#ePM##m`spTv=? zUX!^dvsy6VQIYY;@rd+Htjr>Oa^{-KBM;WrEzp+G{(X)BIS?--c=EoalXOJ6!rK9wB|I*ON(EGq^a>_X1 z#w@BGDBVLSK&^$GkCTO_6GjUG1;7WY4GL^Avxc`dcAlkh>N96^+B;ha_4Gzn?m7UaMpfR|2g1vsN!!9d?zl?u=COcGdGj%s zop1nY1c`sYcd&2pgH%}nGOiS`VS%f(bU4q1Q9-@F@0rU~(bdVyJ*~_z09HHgyw41_ z%my0&M90~=x~Bj3crM2xRK6cc*~JHF6}AAZxaq+EuNMrf%C!*L<5|H{cjUORS%;XxxOfK3`d#j*7j? zjW>fu|0z#nmpkZ70>R;k$)407gapj>;~0+z?+mzbb5Y~HVHeG>*QZ(OkBJ2UFhqk& zfrQ(e#;sl7aJ=K+X{rCv9H=gUk!}~=p;kgi^PL>!rh%^`Y!|_5Mn3+M0}xmc?+lK zn=MvP*=kB$#1TG~R;pekBN>SPPuUwf!oYoGe{}MFbtS8^V}n!sjU+ngQXLu!QxvEu zNm0ZXctI*M$n#0}(YLARnbFGX(; z5;t>)nLNTl6E8@j(;aN6gD~;KSYP4v&8)H<+|x5(U1I)|Ht7ow`jHF)jMEGlyDL|g z6G-dD55`q#%1Pz;*J(U4`4o{1!x%s3CmKou8Bf6Q!PP(|i5u;7@q4Bn966G)AA>m3 z)pMAw;yT62Djh*s7>ZI@&^2XXQulNE;GQhxKGVIl^tvJ(<2KTCQNu%nac1vZ&Yt5q zQAoL}+_XxgDW52x_oL+7vMt~RU9*x<`#jv>i;2>k!7ni{DMah_S`aP}_7DDK(KKLp z5#WWNKxng(!|v^xjl2e}a)ZFLMP(>!Xb1{DAoExwuMUyoG5)E}fi)d-_FVNw}vP#bq6-FYKoO74!o%m{S9)W6PE zfxW&P-q*mNS7NTNjodds|F*rKqHkV%XMOIW9b?Ad%~9;`e8%y~7RJQfw0=Woxb^#- zH0C3=uobc>xHW*xeE}KVMRN>?yI5f%5CoK44VduB3&bz`Gsm;M#c9 zpSbz%r-*U0bn}!v@s@ge7C(OrKMQ+tUCHU*YycP7*3k{jcArmQ_w4|e9K@u+`#u99 zkKwj0JTsWSweu?F5NZdY=Bikk zBn_le$<%Nk$z7=iRESnqX>AlfE^B6NO0=}^F26+Bfe%be`nLV_|3&#n(TQ1nANGn@ zZ5utUJA1Cbx~`0YKcBAxaHKheY^o2{= zWUG_uOYNwZ@@PJ-vf_0fewH6lmtv|C*PQyH@oUr@&XkcqVws2jm&wQ3A}ai7r(>TeMVkah2rqNV!6AoTeg z33-GQ0&+rvq%Z>dK~YRnklQh%C@(}!$T-QvTZ^6Mw`sHWSjvi1$Ae!&6N9Rltlpx7 zoIofc?nicds(#@DyfheCQvKR;>3SJR_k}dp67L0sAf^aLCJ|w#8G+6xp}v}+f)0)$ z;-@+2YlTqdPa|nr)O<|0PDSeu4ht5#+xaA`Gt~B|i;Wo9T_*FyqMERwPa?aT;XQfr zHo3s}3}hlIvz~%XmR@Sea35QKrI=dV`3&mXp@7)CqQ6@?;Z2ct%YKiH6LqfKj0yMJ zcYh;3C5M+=f6;jzeVI&N}FLvn5DN9D4B{u8aI9ru7FpnxO4&o5U2;T)l)aqS=QCnHvCro zx$$Pza=gv6b>3C<=vDX3KjJkj^n9PVI9gWRQGz*Sl7nr1<@RvoQ4loUGn8#c`M|Js z2;reAP#deVFG~W+wEHC@@1&O}Dskj;cinW8>%Av`U2a?M!Mb8nn&o=CpFOdh;^*u)L5=sl7JiNztc z!|pph$aS&qgS@MYvrmaj@80p=A)7~qo9?=$J7+G5Z*_B$56LT^JW zQ{wR;X@V;?YNNN0Vo&UI45J7fe{_Hz z2}5#Bx7iz?iy<2;MEh4Vk5LT(d~XbeDr(v{m4+>3VjsG((aEvxAOqqKPeOrZz#fpB zh=#hn_?RcgpUv>VXZjyi01G4rIkaH>>R;0EF*? zNUWI!AG-eRXuL=YAc$qvZN~ti07EVwZlXruZxEI^aZ@QhO`TZ2_t;~eh$+Z-lz%)p`5e+{Wf>C)Jg(NushB94s-7r%Eo3o6{eUY0T6Pqu?Hg;zPvAa(Ye0J*j|>5 zVH@BlfYukGz~C`EbIi9+Cd`&i(LExe8;u4-3=UzKhU( z>$XNHk4tQXjFcd#8dGFi?sVTKvNjIviUW|bce85Y>%vTq_iUo(J1F6tWB+of&t_!U zWDfpE&FKAuI^qdG50Xv~52F9)o~!4W7|Jc00&O3lfVm|+ax?j1wt?$X9r11D+*Iv& z<4<63f4q$~*u*G4Q~UXu_t6$wr>Zp9kcB-?{ehr1l8;FmSjMvY4H?T26|HD zYW24^ec(BXU4a7ntEbiuv4wGF5fdxy2Bj_AWT?094Y0+QhyZwpmtUZ>bsdqT=KYos z2q_|Yo%4*doGw?`JZk<;2dk|S=@bR2lr$})KWn=#b#Bb% zE&Y?#gHLGX?_>}cKExbSp6I+iPPQm#cV!s;LR0PYn^?`-F|p z=RMyBygwq!0A#$0S~R#n#aMW`#4rFVs=lC12COcMAE+%sHb2S#;2($M(*I6cZ8qi*uop&qyG3Vu$}i_>F3Fvf?%1*z@F5HG zpgkLpgNhy_4EZ8F!HNsp_@GIctR$Bc&3{$skzvS%t{wvuZ_1J;OTeWc524&XCQ6Cr zQYXTQ9C#zifijU5tg2uZ6`{jeMI_ak$6-|!?>WMDv$ky8vYYd#D&g4}aa*b4Ied^g z-!c)aEg-Z&ZcogrVFh!Lms*Igi*qP>@4A-7-|S3W@*K>(-Ll*Grm5iWuI5AU_=-4q zgX^e!ez*OkT|4*cV$W!6(P(Yatc~%ile2wa{P0pSo<)Do59H33m)OSQgSdV^OHJpE5#GVtFuH1<;4Xgx@fME2>cUEeMg+s6+Ll z5SHds_tyhiihd0Jo7|s_l?CXFP+3_vk0h5zXuf+;kh0~EEfRg&YKXV}ur^tRp*0s$ zA0N%&trs-#tQ!qA3$rDJAYlZRBx+iCn)%qVCd*araCyhEZ!DIybm3WrXSJOjX^)rS zd%CCG{PwbZ`mxY*H+ttIPAckScL^Gbk}m#tSqXm33aN!VuQbKJAQk^ViL)b2GGB{6fBlFT2hTSP z9-;c-O%?Vxk+`B+3>shH+y7h;zcgCLz~L>Z#yV#^8nAH(5rzO`CV_b{k5isIpunI1 zvS;$vu49|-tG|(h*ttAz(im975L8aP_UQ)?ZcTkneU!;6{8^x>+j71_3IK$8qt9Da zo96UR7XqYscywC?C=o@nxUTIx*TrP;;Z2G429qY`qX9WqRax2}04e^bb!#lB`k`HA0zB-7wx(WxGrAZf-L&;THQ z370dB96)I}$M&~38Gkji$=(Sq16r|oNURhWO6WnLhx>=2o1Wx?;1oENjt+)WDCB4g zgANOuBuhFSh^Pby)qbZHuFfTMw-3uwxmY$=u`YAF*gLU%2zerd<2U>T-Tb?0IMQv3 zxfK7!xXCD* zE*2Ii4@35#S#K_gD?7AAPPbY9mqa~(>QTPem&#b`MIUUKxQRLG!sKeewFK)bSM$9T z*+BK+zUvo&QAJxeX`7bjU&+tE#P=D1e4M=8zJ1TLR86bG*pk{J&)C>6^8BqTZLVZb zM*10LbF5kj*0$mq-!@N0uRGSkn_9416_sYtq-+Msy`RBu560+sD%$MoINL1;H0Q)L z*G4pr%U52w8fv&YTR6L}HQHP>KVz@8*GQbi>TZiGeujEPd~VkbNFCi)UgGLd^g8-9zgIWE!zRtr4-KUf8oD9rzcPqstpUp%=62$hv0guLG(V*@6`j;7 z&>na)*eqGLw%V&t!N<^?!P`>naJw>6S`pa+`w z3m%pXv&K3WtnAXw{PPJ8EC-|ls)=zMVb)j;Sa}cm1oo}s8eh@+G0{OTYSFE%0roal zzexM@Y4dV}dkEU5t%HTTX~`P(-bUpBcmjm1LB?1ev?2Ykh7K)a^HeTvCdf930iini zZ}*c*wQ1!rA0o)hM_>|tZ&OUBtv~tV{7fhAt-sBug9WzL2evq_=Ur2m6CAHdXAPeA zzS5BROqfz1^qj@DRP9_OQz|@*5?nj#oMcN8HhCGB_C=??54Mw9J&Zn^iVBU54i73! z;mFkR0V*4iB$v}5h0THy57nCmYd8(_ra3LWGz}JE$Rd7{-9RE3bX9tfS|NL}O&7s? z8}ELs@afnA^?ubS-t^nh_L4hzb`XqMctoGFs+hJ=ktt#+{&V11wMFjwqi;TAU8WDj z{1JYlo$ZWzj$xn-S}tvE0mTN#f@G=LC45*rm}*feg85ClhuIYI*p-n zF$7Y#M3MC}Kmrir(srS_6%GME6STqaZcqnBd&e!k zM}EJQytyQk6aRtRz*2~x998+OH<~QPkVZ=xL5C2*p!42tzW$XhiWn8}OSk%~S==@DCCxRe4om0K!PrAj%oslI>j>c^zdw!CnLox%V`Kv`aGFzuk zUSl}Qn6j6>B9!Rk3%7gcWJ+|;MGT(j*F$gcqR}n-GJNN8@k@vliAuc(C{VObm;fD< z>$n;@1V9ey1Wb@LX!vO`^FRZ2L$zR*-ibOn=0s#wxps>ISFlt_CtfDNF;Jk$oD5R* z1(_f7--=RBznqV^%IDkLTY(42ZML`YAHx>WPP|^O7q->CLzh+kKoO4n*^e%0qAha( zmY!Z+Pw9WbHM3`4vGmxz9SAoY&8$LhTA6LhkGJGQl||gbC=lMVdSG#_yW)Ol$_^B9 zEAh4~_iIE6ke*=U#!FZ z1|&<)>zhA1t0Pb{#s&AeM8!*$wctB-To4l`!3HYFux;=d`R z=*%x^QbHohVb?{EvaIMoA$AN$HVX!Dei0ZCdxIt>2pum*YuUEMl%h%NVJ8dr^TO0T z8s+VN!}Q1Kd(o|Q{r0Q~ju)TT>(f5_S3W%WGRuD@(~FIn%Re9o##9@GHcbt;jDfP< z0&;PInE};xbHA7~gIve`*KktOu_N8KdqqNMiQ;TxhFStWYfhE-dDgJ=-qTpAb7#B1 zT>V$|BTcE(s!DFtTVZp#H;y;nrj|?9FO6g6f2AU{z91&LBBWV6AVGg16I~%w4f?hv zax?)@*ne`BO{T{ zy8iicj{p9Ipp}2Un?T}$LNc2of$)E~_(6n|D$)(yGySTOFOMJod_aQ`F@XHvnsdND z9)bU-bO!!O_$N%X#K~vLECR!ZNEFkw@}!fqQyOF3Hv~m&Xo^j-5vYm9UJ2FqV8I`3Ru1 z%ax&9v{lY071tk^y0bhYY%E$Qci(4Vf}f3vFjy;(Mv;P@<67!roi%!r6W{S+NXPTm zLLLqNniE*UN76*JB}<_tQ|t*r={Kl$bj=2~sF^Nx6t`qm9UkeZtLeP`5+kQ?)?)I{ zU%&rqFTe#IRnOZ>5r@Uw(5RCOheOt;d9G`$#o3@J9d04rRD_js8TJO{&%IB_v4cPer!U#Q1`qkvXKLPg73IfEy( zo$Ejk8Hz)7-As?RjBf-~Vh(2F7RXopf6SHlU)mn)f(-K7g}X4c8>H19+*t&q%bz$# zy?`WwRfDgxN@X9BVP>^xs~22H_G~xKkSu%20K)d+8bdU+OYd;f6VoHm|7y*Db)p}^ zf8CLJ{N0Wk>nm)fZup8Xtv#CxsZ}Ggs!tOkQ6q(`m^ObQ2o^{c-$YSm&LxU0IG#~k zn7vFo#BnPu*b;RG*~nv*-U!qzX@fv7@L42cW|0gB{m#|JnX05rIF7#UfbHynJk*2{ z=R28fpxL@pZtI8H#0UIevY9c`FY0eG9eF0X$A-=DG3q}<4p&i7{>{xBJH>l1NmC;= z#yUHNAM1L@r4E%5ApC#95dPKN1#r@h!2CZ+etM#D#6Oqz|Ej=;4po{Q8~+(Tw{QJ! zVD0}xvu)pD1|A?(SmM71(RAID)JqPx$L-lv2Yin66I?e=*2j$$&a4)mE&)my>A%2J zDr42q25?3AZ(*K~88BzmtY$@5ZSB|rKRs^UjE&MUFx??RLj}sAWiF*C%WsYWT#}&n zbdD9{h{7|*&$74HX8i%S&E@lb@a|NCup5`tMGA~FZGxxenodAO@PrUqY8E?+a?Thv zZ988X#GGaDku>o1mVPtN&UV3(+!f$2?7M+uj-wMUMx_4 zs{g*?S^>3N4&(Tr@4kicO7SETNGDB7%F4?BS^TV(SDdu}GfTu5#*?(qkU~E1YB@Bc zYJ(*eC^%12&`=L=Zur1NXv+Y(Fd4Kin>uBX8Md=`IBlCOv_*ha?pHb;!-|Eg5-Wb3 z56zXQ2@G)&0Fzx@GR))%4REzKj~Pdbh4B?{mHtDfpNe5V|M$fVN}T$f1N8nR^|2>2 z*2FtPuCItmB7#X-!x?Vs+EWT)RX6YX_n?f9r;5NkoP&k7kgZhnv0NLW<8Qi1EOWG( zKS-O4Q&OXJd}44-d;Ahj)Rv3Qz{De-@g7^aq@BfNT^|J(ed!kj!ih0IT`8jq;CM)X z5dXK5ti_@Ku@GA~%aiG>Qj;%TJG*U@`{@6=#>6RNRTVN2iiz!I zz(!If^M;T(M0g6|?{T1@b;)vykZ1k!L_vMlV~AN&ng22Q0I648tPk#8% zXPt}eGh@=MWJ6bFcV9QHHgyTGmfw^zKuiS)cLeimw{bK(6$_`-{G`-8#>c8n|6aN1 zDQOk6)C6t>@Uv0n3`*TE#80UjDbd|)nL+c)O!j`moDsVMLqAWVYiZP>q-VU2?CG|L zXV}ZwL}n6S`L%rLMSr86yAu@&^=WyZ(RXq*Wb{Npk*@zs2LX3P*CQvWwn3sA#T|~N z$<`A%UlR!7$K*N5eEHf+yif>tkV zhJzgN#_7sUV7z+NBAaGxli{@0MOR_UZG={%t*^7gI;&cWjlrG)-6fhn^z|NDC~bd& z4!+X~I}Z+q!2sY37(=;#xr=2G>*x3HsZ>ti|26slqK$kZ*oAuBn3a}QR@Xr&hM~sx zVjc5PUQDZH-e-Yr?<_8(w)J_O-s}Dj=Uf`;gT&lf9cS}{CUf5@D>in5E zqGT)W>d^jD3JHTIZS-jJb#RUhEngDr3G?Y5)IT8P#A#V}Owh$)@h#!_U1<6(z12f< zuY>+Q_3di-Kz2A&icOw!?*)U1`=7J@!H`-r#82my{C|z|X!IW%`_T$1@*k{l;nmQi zUI`%m_}@R+iiRXj?3Eo$@<#{bg43sqp+^WGL@JZ6mM>q#s-gqn`+tLD!q|QG8Ky(a zAQIWxR<`PMC%Aw?A5|83L1N$vqaQL#9xHSm&4#sIUjE=(^bI9G8ur;UuqzpllTf^j$pe84EwEFqvF}ZvHPMPRzewxT2=*r(FPKBG6u=>nkH`U9+ZV=1 ze`=s8Q2#E&<;<2G+Ly!<`JCaCM-Cn zWHGvk=>v95+->=+4tEA9x7 zbU>tec0)(*VhYn!`)FR)vifjZLhtio?rvW011J7|GV{~0Z*Dmi$G^W5V8~K0kcTUe zD%g1j6QEqFZREQ5KlzdAJ0uMNu1Li(2AKa|;eVH%K8Y32>lL`w2}QOz26deYVcwDm zKqUd+Be!Fz)i=2)qVN7ej$Q^c_wcD6L6)cX@Wk`2AObA1`L`Y25~ zxKOLw{oX%4ecgo%Y4A~E(o@q4Ozt~MXuUDWc3Sni<&h?z=vov%t%4PV=R^H#-ItX> zQ6lDmsJaRAE3v@p0=@q?2FY%bOIgj40&BOI=q;F4{?Az#qL*Hi8E zz9Q_Pca&c1q>yN?$5zVIovfx6o&!CGXzCv|qVCef;oUBH$TSFy_$TTAH@3XO6C<)o z{&TN#LDS)C#(~P{Vyk6gjDawqp%)eJ+3|lbKH`k%7vKioC_(W_mLAnyii>#{H%QXY_GW_+Ihzy@{lzuL6==_H zQG0RC$I(+PaIrfpt|X^TZoi_-L8zPko=OKcYXY@H)&bXW8!B_DtThOTT?pp>cX`eY zlWP064dWwy!P5dyi{)o)%k4bIp7QSB;a%gJzFU)Sl2?c057fJ7{c7+1$p!*s2;~&u zBzwWf;w-f5lI2^i`}~E9hL{KIl6-a8t$kJ8XYXMa|F5D%Wu8^5-_ue_q^JHyH#J^Eq2|fp*UR^58NJGbPxf{LOtJ)8 z{EH1CyNTZ|yz||!-~*bxi_J14xRD8yBsHLpqT`d!59&F6P2(dF2A2$?Rs(( zMu_AGS!6Xa`$RkRE<7cqV7=1e&d6|X(`z3>oq?%&#Hu4<|+yx zLSdewGM>FfFpt?`_T1cLbQ>Gj1iM2%4(f~eh5zG47FUw({Xzo?0%3-TcN2yFCo2D) z+W@w-C8^ZMS==u)Go7xe8%5Ax1QOh%#F7>0^u;#zcCz_!DLvMBk@s$d+_8os!s=eH zX;#zLH^u$*%T)TaO3oGtc4|NUY`Bu3wK6{Tw=5XVsBpxLC1SBX=BaHtuOW% zbj&**zCcLSWiUWpCN#_}441=9kpMya(Nl;FECmV9?3UZAhb0ajmNGSqZb8aozGljr zCo#=fD@!&)0{KU`U2{;8lS)OVA~XuY~oBD$5VJ@D3Qop zal>19gz@jsKSY0Z2Wg?3P9wrE@0Tz^Eq&VnPtKIGT8ZvvB>3uDYJAv|*RMSg#m__u zPN!MKAA}nGfyuZ#vLe=?T}wdzO~`=4w1v{7>z-6g%s>nDSz z4T_OsV$z_JWMpJeondcars@HF2>;l8u(VvUe2SDf({VwVl&yiU85FNn<+ znMJVRLRy{&K1RLBLHddEllM?bO5tf?p<*;DQl*N3N-@Ym&y%cMo$XP;>voA`+shu0 zkuYsouzr%NE@;l+o#ukx8jGN#ia?;{z0D=Wv*z|t+5Nyw7(QBoJN(;~5c3d6=(Xz` zs6(Q^L8omUzM8#S{Iw(z_#kO%ZeIU+Q zG*;$XCM**yGeu4C*Q70m`C-#7!DJVBi-!DI^rSBu?3P9+sN+Q$2%d71%DCO-9w!Am z@wr^p8w6Y}D3iFb`k$whHS7pSqan&ty~PXNt&d|tiV&^$!x>Tc z-z8RRosl(|WQZjLp(27%2<8w5SY%`ux#!gGtRJSu&7xoIaz7#Se9&hv->la?^iIe_ zl}#K+VE%kTcJqYLstj#LvCSWY>tPv(zR$Mf*PmNWcGd8WZ#Qu-3Y7bo)gPgWKVLuw z$C-S3lAxdQ2MR3Lt9d>9FF5XuBf{Ma!IRbI&5PJ+lcmj`v|8kDb#C25;R}DRlvVS2 ztR;H>a!)K~wA;$^Sw|H5yyCzSgwjJTO?iU}_qN6bwVTQ!Ia%85d;=mXjsE-*g_Rpl zV^O$4XLoX;C3g=Vgd$Q%b)RC`Vdpdw(Yp$xvdqW2FhZ11HhTfzb0JiXx7y|C!>gp! z$GDY8ZR{+kesgO5*6v{enJc!$XCoD~c{fvg>RPM1Dhk;>zhOVnfXMtnDV@l@FA!cY zGLPZMzTd}9DJJe(_`ixL3BC)MCq0@QAUL>Y7jB zsC}gk?KfgZV9vpx8cpoy`4p3S=|q?B@Lc=Ei|* zXxB5y_=Q|m;8AgZ${Tk?&SOmuMG}^Z1Oi)|GM~LXz#s}o1~<vz{Z#kTZx3g?okvM!cvR1cph1b z0c3lpi~tc|vPe(KJ1CkY9N$23M=IUN07Fn2b&!@^sg4r@vYS9wp=_keX0gXgyHT_e z+&N{#SLGVFkOMv5qvf!8PZbh=E>xRSRH%%LxF1HNX-g*fBYe&mhzhs(?V##Ax(M#e z1d0Hi%bwr!h;Cq2&K+^O@NkiOTVXznPsW|o`avvHs^Mii@-w=fOCx;J1P8k~T+~h6 zv;(x|?az037&V*uvCXg7=pj%0h$(Txlv}FY#ka6AG9wGeK^;yoJ1hC2j|i!3K63N7 zlFjHJNO}jGMt@9%XJ8wVN$+ITmopA-j!JHtz`$;?v%wub_UuF|uQc@sIDxKRj5ed= zqC!B#Wx>katIw!j_>u7)gy3 z>Nzo%Mh?z&l@AyHiw1X^O$e?rvrX~qXh6ahSwF4bw>1WjWT^OnFEvYff!;i{S=I(O zX+aH66+1T;N?OKk#hxvSS24bCgZW0F*@R_;;Pjex{Gou4ELU&#>boM{u$5Xs%v7pK z#3y2kSn$V)Jz3mA+)&RSkV>d_m=q3}HJ)_~$}}BEf=>@0%9GlZ7J@RDZFf+fhm((= zRE3tyod>V7|A2p5BRZ+q3Tm;IvSKU{ZzZsP{*oYji$}pjM+p|(E3ia4p;mM!u3T;m zUMZ_vxe!BtpH$`OvoxSaN5C`m*!596bNQe#qcKK7eA(}|WndHXQyMcV)`y~^v&t$o zOrtk`xlnPDl2E1EpP^8yuktmK}YAzE)9qzi)b*)of;da=5mU`;rXG$cJX<0 z`%X?tB}{h*u^JhXKQ)xR3hGgc#ZrpF2*AJ1+S%9!xpWPvy#z>4O{qwZM4@KONrbUk zW2#&ff8WD>t7+Sd98HOE`>lIJBTVD%B_qR!8p)?Fs!9 zA%U~mYtR(7d8(pyNg3r3Z*7lE&h2u+dMS}m$fRI?T-LRTe`DQS76)bp2Z| z7K)k;9HaML)lt3N&GdrQv|7Xpc@I{0&^KSEP@)-!&U-5df>!dhDLwP2Uh7}xv~IFB zli9un=2nrC{rq4P-2FRphS$A#mH6btWipr!a+C3Auk^+<=%39KMpI>B!8i~Sgg<}7 zsbRbX+wNb#nzfi(x1Razt;fH@z-LzK$+3|0)`9=vhlm~R8Sg%=vz*1r0QdAIsywNs zm`EZQT@Dsf#x*T`)1ZF%F4)3ba@qLmwE6pdh(Wt@sht7-N9o%Mv)hh(rFPXg(M=uD1BbK=f#I{14Va7jZ1Ys;OBLh3H^1J( z@`vXbe|Cg4jP-{ooqZ8dq9UOrfB-^@BSNh@R15~_a{q1If`F<420kcMi!F8|;cj5& zy8x{QH?TK?a}Znw6l!o#0p~GQwhe+2k6gKV2m6KssREJzr_v-{)4>9uXT{ZA-yd4{ z`Z_Lwy!?V7t^;SvUbwlAK0Q+S!%DktyM*5lQ zJUznf11`3vC33q7xGBK|OHg*IYfwjL;t^3#L9cJjMgCjC8(;Nm?NGVZoNCi^rPiGq zp|^u`hi^+RcIvQ=D-*<|fpi6+<4-S4PIi8-`U1}bS5@Yzs4?~86;08Vi)6jXz5Hl# zKbE`nV8}b#`MR49{k@~$m+VM^<1ckh8Vj`N0zb$4_`t%gDT7{ZL^*lZ(N|EugDxV!l$iqe>!hZt^PQHQ=RS#*43$Nc8GM-ne?JS0U2-VS#rUn9nN*>jFVSQR!bQnN>|(aFg1z&yml& zv~;6j?xGw=GBXo}QR>FR1Hw?NmP(j8&lnrDrU(vzsvqJhOesN}7PqCY5dk$Cu#Evc z?nAZ^AJr1T0K}%s#A9#l_vkbgAihaQ7lDYMFzb&>DxPHt@TkBsHesqo36$ke26UL> zFsn&rQm&Z+PXP}#nwn&QvNLu`+DW*>>k%R>27?|HT_iy4tHpT}b@@q6Em5=AUgI^X zu(UGWOf3Ws>RA1Lz3TMUxo~+~2j^Q@(d24?tJTlfi z%=`Snh=O(4=VLKjp2@4HxuI?sk5KhM{fK!xjjy5PCYRoyFxl_;xCrD`$$G|LE(;Ya z9|gztDq5W7Y}eUtZnJ}%it%%M203DWU!Gi-YGy+QB+SeVK7C%hlHyR6rJESL8Zl|b zo70KDCv+hpritmW-hA1)F@R5wcjxIAwyhGSqaiTNB8=A;a`Gdh3z(fyye#u&iU@2A z*tC>GycEL3ri*vW8v>tb=v<IOqwQ`+#&Q+_L-%atX#M+uZgjH zouH?TZ5`1ZbFa6z@7l&Ab$sEr=bO-6nE(qb6S8vgXQ;LK8&0IwJg?In!o~3R*-S0` zM#}^pk&5Q0K>RlKB+1aur9HoFL+vXT zJx+W*?UA-4k)fcLd3--*X5N&^YURM((I98>x}gVW6iM=nrnsdjE6sgN{RBB+r#rIB z%fs@`);vz`w;rgbi+Yz1br3=wNtz_@AdXr1U^%SLi4FF*Tt)0|O7&Q)8zuQHfdeaz zAj500I zVwhXv^|3(c!0Er7>vmK`j*2`qIW?!!!Z1Nx-A%^c(@It4Ka_DgyH(?-_YU&H++8?% zDNxwqyB{K`;GsJbKgn$7(Vcjm(iQ#S`B2uHq|6Lma%csKRB-U|=yG04JxDG@5_L&Z z2jzlACK4_$^z4^mxFY8bns@=W(C;>*78vHcwnZmcL$CEViMF!d0Z12BpPxN$ea%m* zA0c3Z#l*Gx1>I%U^GJ=!qAOYE@5jb!>N2<@`{PTQL4-KD8-!L#*)#lnsfrZ&Txkel zl`Fwte}!45>edX)!j&SmG{qO7WmaWu2rSw-9vHQiCpo$!+-{KUlS9}jfQ^T#Z6|n7I8o2O+Y5`8vA_>^xuKP z*h0HcD-K|bydGEoEP={m*J+oak!0P%)P&p)GV)=B6309K7s9ko?J zcQo%!u))FRisW+Brsv+>$ou$oQqpv(z12pjAXLbZp46ON%1a=A9AAH`<)Kjm1t7fo zPx6Vey{eSW@t;Xua`5cmp*bW-^53k{dMz{Z_eT3wuAdbn7b#c}3;2E~28chjc8aN? zmTq0;N3f)Jup*i8t$++ zCSbKo!jNn@IKcILf4L~}cw{|+3i?!;0S>ygcw_0bnwXMu)hD;LmDx6d@wyi=717gN z{dVH={IG^T{R}`T<8IX%J-6%6BUR&1aoste!&$L83sxNu6LN(fj<;kPpZqP zdAxK+9ws%60{;1ghey8UNW-8Y+yqFGgAdnV#?5jh(e$Xbhf5@zSSBJ{q)jD+ZjOC z%zxbH@3haGGdaD-dQ6F`nPej+5J?qV8WvN+lOE2m&D0`@H~l*&Pz_e)Vc4VgUMtnC z5Z^U*lS(Cq(mG;PN~2Q6wxw&1iH;5c+kg^8QD>o{Qeog=tB`I2FctnjVL4qX%`5%7 zYs<)RE`r9a$tt%_dc706JWFm7$>1uWO#gqbB!xP$I-^9jdH^8+<{=uE&j#7qge$Rh z%fF)}n%pt2WwIYCKn7I*@oL{Y!=zM2u;9pB#4bVow{S>_iV>A+BvsnnWtaw8jiGW5 z*XAQo9-+Qs6z+=P@$bdSl-?xQE-_{WFnUVIC|b9!x)}4Ir1z=zMc2BT(%2 z4eve8!y6K&9fC8W=S)c{h}vJ%M_d`>dQeKgZxrdiqi z8C|2xO864xqm@M$7W(#+(8EgWF;SS{dxYiO&f}`61Vs@OGwJ}T64khJLUElf0M2o+ zpOIYfR{xn&^*w^a(Y^wsdDj3(-7&nP2X%MT{dnuJJ<$Zj4m<4GN4fX22VRVxUqGnT zy&-}|dc8bm&xC%6Xgntd7axS#gE+o_RpFi1mt)V~u6j3(Q+euxqWZe8iB+$IgngkA ze;(Q9Nrm~vh~@cqk8GEZ)Ho{N$Dx1?5-DedqwZF6SRDV>A(Wl8wSe+Pi za#(V7_Z2k;iE}2VDQ#jVRmgPOHzfa-H=!3}SmsN9z z(8QnazZLG>W{uBAQsmItv^vfWWpewcRd5tO8HE%d^(k(k6^Q=C3T`>NF+FjZ)74o|p_GPj1O}nMH zO8tvx;veYZw~ra}Pe^6QaSiI^wFnH_JCK*uZ|zdEnluR{r=*WZN;Sk0@#)4r2|vZJ%V;e? z!q^z|t^y%z3xBblf#I)o@N~IL*ipB8BHs&0Blr3Zxz?PDZ<$-v<+PtodUnPl_Ydr` z!KPt|G*Z5@BA_*rLX@hR+n!AJbKn}hAY3o8Rp;`tfO^13B9~r2&QD+$`?zG}!K%sHd@wM%NQM+N zdWb;g(|HEZZX>1SUi9TVtP4j|Ne!Mf2cXTYW8c$CchkY+b%AWjiaB6v~norU{lYxmTgL71*p31JTw8iGcNBt8_eL`!u?^atw++SLtTS`>AW?}8<))-4xhU%dIRtX7%(gBo5z|4Yj4CoUHc}B~TjMga5b3(O z@%1IOf2Q*|(j zV>A_3$K%XM#u3BglF*tony&MUDQvV!!ZecK%=FkJ`Z2>;MJ#a~G`Rgl1H>tkY1Q!Z zlc}bkhH9xhdq$4#jF(6AxIn`nTg0Vh(_uGgNIq1cjD#na8j;h+1dMt#tM(3h1k7Fk z+|t>kvEsCFrg6~8>1vQ9>)9SZbR>QA$a~8+j3-)*4DD2lgFj%&H3 zy+rplB8H>NPBw?sSc{U1ah^I5uVdrChwYa?wthnJ+SiX%{Nuyx>w=`=nx;0Q!(wUe z;B@H^;Q}vsifV*I_jwVL(ZlZLQdIEGc0=3t^CNX=AN3v?Qq&D&q7pB154mIuv{RwYiS)X2!%4NxNE_qUy3? z{WODg)YUL_lXPGo)bH#%q10oQsnur}zkOCNqn)r2#+QGlapI1PUUkF-DyRXp z#D)=zk7H36MPdeVDQ4h3s`2NITrP6WCE~HJ{ zj-k_P(+7rW3_5@r49YU>D=EUHKN%PaIgQ$FS5c)&2{(mE)5qX>@oaXvHywQZY1=V4 zCf5zX4G=c0@GBcjibvuU^FZ_*zeP%3G>V->iI*bX-oc(*e6uN8YHI`JC?Dg`%)&JI zHguZ!nW1}o*P4)Zg&R>A^6*#^Sm^C7WDmPUXNapkf_^nJ5RGvsY{>rfnH$Wx1@8xl z+9|9+@}e+4!v1GrC=BniR zHs9(dAD`li1v3pY*G}OiwwN3LjDB%oTLxeD8LL-2+wPVu4Rov08q}8KLcsbO>@|P^ zo?d|vE?dk-LiHE6X0RvJ@AWj7FC;`;cN#L$nDm_PLdqtsW3j zxw-XE&1!~tQ$p};R;`F}$RRf1FHix5~MU{mD!~Dn{4SipRRL%SriCk7say*mJnW7*8#b%RJG%o&s zMB*(#ByRfzl;Z&+ahBJAMB=sJ-<11N3oocwJhuJ7>a`!Cl8kY0Gf6k*U$Q&_Awc7q zl@{EW__Ycy`QNx9#(&|4a@r_>9pD|E2kug4%W2<9!%;I$iO|hO@#5LaQb_>y@IiRDjjHgmdvl2LN|apb~K2B3-U5-uX-LB6L*5?nuze^R|OkeZB>JGGj-{IH$NY234MaR z;rRW*Mf&6V%&%#sP8i~Mq$t5t@DL*Uc`gIZ^lj>^qj^ftY6o_aP%o4b7YZ&80DM=2Yw&9jvY zbiyBmXavp#VhVYT&&Q{O^(PKLl+>+FrXWF(@xSsyLwxE$F-Y^{1uby0P+pFOl?7o= zrI8IQNfYfUqo9d((HgeVhOPWu)j6=#A``l3RGl=jCr+j}IyyviPAu=>A(QOFF9=4Pc)KWzn`n0`O{9)@R43 z43)>@CxK9D7{mKC-1-j4qwr)jBkM#M^&#}|&@y-BH>yLB06ng_OJgqPzcQK)zEUAD zl=r$j1*+oqZbi}!0T{x3mA<2hW({Iv8H}@_3}Bvr39J{E52-5Zf7u(r&V|bixpfQ2CDVuSLg`l0jOmb1`Wl#$S429iA_s zmj)19n&fk-=Jx=XIS*4<+yllDKZsnsB?gsxhQ8id-->fdm{j+kv&#U{ajmG5EJh| z@;yA4N5d!RRJ!~YKJJ9QA^u~cIFDhO2;1akQmzsC2pF&}r!99T)54Q}E#gyrNTz;R z2o#7vWbDt_Mlpm@2&T)ME?*9pc%FCki-^QpJ?rGzOi#p(MaV8tO4S>XvwA7{iWqxP zQq1z=LSiBc5MEI%HdqHZXQDwf)17g02{P$AMfIY+c{Xm@Jb3nV%AHPk3nrbAYPHgo zo}#h+tup<6TwTGx7OQ$NDXwjaIYQj|<$2HPeYNm#q}lcf$TiqLeEM;~^Sm%enZU>( z5gLz$c-VPtlWl+nJ}-d3<*AQMfUM1O$BO=8RSUfBS8}>n$#ud{%$FG0{f#p^jN0aS zt4LYsn>>3bPY4?L(-m^kImRlb;p{qN{iCj6S9I)eFtL+mvN8$l4GtUncJh4g$P>1q ziX(+4WWq26WCL2yIMkE~6!PjN`qbpjx7!i%lS_>a;4xqyRu1A3vr*@i36Iav4_#NS zkaO$N62uqxR#n$K49e?~YpV-KKx#$ABI0rKD@-lnaY``$Lr%VVYBzs^lkaxdws#VX zEQO<>Mx@HFN)OBml#M<^k`8sV%&#Bo?`1qkY!tAh3`WQn@Nqtn^S$`_GbfJPaY6ip z%KuA>nko)LSLHzRvBH|NFo9l`h#)^M`!<(h*_#t7G%W<0Sg2`&zAKRV3GnI z&&kC|N%IvmJxyK3ysE5@1=bT#A(^VsV@j7SU^MrcxZxxR7&Y|Z5!EarsdDEr z0xA@MHNl5G%aPIl)0s^;yC$nrEa>&RJKTy?Z*Byla!0~{;*RD&oPFL1njEIr`5uiYPh6|2h&xp48fQ=TntU4slLAa`1AAZ-#HWk50MkIrr>= z>%8-A72K`sOJ8X`LDae(bF+X-OkqkCQ&bnVs>OX1L22(oqEHrFIf`cgw`UUKl1xIqEys7Dz0_qcd;N#YX!TH^i)II4yL4d zLPCDey~Iz%x?czF^0-=EuS9>M^po5tQnz%t>!S)8a|oBs!k}4Xt*q@fx~7+wb`a?v zV3tg^1r*|$QGZlej{jgtE>#X`%ilfK8f4l-i61}|NRNyID~c@l-lO)@h+v-t6Jpgh z1p=0!pi#_#flDR8nn!Q89IIWwHL)Zi)DfCgY_#^}&!bh7mi;BF&b>4zz(*)E>k+0S z24)f<%kVb8{5e{@%0s!=9V%bfLtB<((S>VK_a?mxeku?L(c$&!!M;oIV{_{>S7$v= zf6OAjHOUW|Y{7UoA=-kTbU|-;7cSQ!#1|Z@*rh`v&`t0H5}+|nalO?5G@KmPT4GZ~ zC5ZQRJiuC_Ov(BdCj=!G6MrllJS_eDQr$_b-sabh^sklqYvkOxQR7po;Crf}eEjB7 z^>V?pM*Ut*mr1}WQe_a(2Vx{#4Ve8MEflosw+8kgAqhH92<(LZ1=IcmwA1m3TsWA) zt`dItMY00=B9Z(*e32Yr{1LTyuPDK2Tr0xQNZT`nJL{r)0jEi;O~g zb&@$Ml6*L_VMqcKQ}<|i>x1Wq=m3W z#v*AW>T-2;tQyG=kBm;Wp&1n;o6cvsPun=ci+A%c;NQB);Kk*%PdHdY#-4WtNptGo|ny51#!6vmd|~AxopQBu}H;s75lx#ZWAA0v9u3 zDMt5&gx12m-W)oZ)X?xn_xr9`7&{iu7Fxg6zNPngaw~>pV0Ri-%z71eaI)&_SMj_58hUB$6OCb1h0KjXc(NcEbRC?} z6jI4L?Bcz|9aI@ta^0V%Vymh$;36{FH4E+pjRlLQBN6n((C8UMh6Y5-$&=i83FE0g zCy5h;NS6ySI%A{rS|z!@Mtd&MIbeB`4WD{x#tI}nkQzqaYR>DslN8HiRZsV#sQBKU zGXT;$JL+wBz^?2yagA%-mgWy(T2jYY4A0`Z@#oU+;$6lLB@ zarjTsp9mEW$R9DX6Lb>l(!ixYf>FZ{@Y8`H%a%2L_tU|&I?3X&6e*Mk1#C9&pgE7o zU)lqJs@4A>5Q}@S(Ed#b1Kn-P@_WUcOZXaB34jn-bSwmQ`gl5BtEBF&)xT-ke>@O_ z{>uY#*Wwx;I8A*wp*o2e|1io>aEptI)hPeYkzuL#)w&4(KsE&&d-LJRwRXLLA#1p4 z%H*D<$X(=xiPxYoTh>gt-jGrlSkp;lWlbBOls+~Ia)`5N!cidn^!p_O8E{8c z>)x<01f$M92DY_#{IfSyhW;rpQuE&TdZ*!$53Mfs4^gdl$oa!W40pq#oZB)fZbBKk zX;f&@;$+Fv6lmj}FR%^|a6DR2z8V#urA!1rlZr~FQPBI|juJj!8_`O?2j!rD#D2h` z@{ReIo0pgVx6H(t9F8F7Pjdd9kY^hg9^G3C)HR@`qBK0e;YxLi8F+8=@7`OH!1ooZ zc-*dWodmL?0?;1CdJf$CqIi22u@A_NAwU``PTY9&6^;(_GR(FA{lI!(1VGi$t-~4M zd66K(AT!{>eUx{zkKs7O16UIS~Ykl-;&`rA%+jQzS(;+L)Li?jvV${r5uC)$NyACb@jCnT9&T%^3(&av$jws6>V z0STf@Ki_%w5Fm;V`fneyf1*XVnW1wd!%o^WBnrDsR9F+Fa0V}E5G5=n@RtJ+zoTe9 zfSUzmfPm}*{v9L=QlzE+4)c8D1|3pBL!F8Qr2s)OOQC>8Doiqg0`X4KO1J%0q7wEu z99Th7ODnWgCR6UTA%3MquZB+c3Tu@nBYmISfJ3sFlJhtZw;Wagz4x%*eHv8O-N1nz zaXo2sL5en0dq{rZ`%N+4^kKY7w?pgWmbc!_>F*lN1T=oJ;auA@jK=d-zG;fIHk9Er ziq_&VMMu^!cEQ17i1p zG!irn2)+C)|5RI&@jGn(zxQ;;?>|V_Ea*Lw0r6DpBTaK@*A>=BktAT#&Ab>m>Qzoj zuc?C+mM&)K8~!i7;#TOh-2qyVF$lFrBIH)qcRB;GDGQRTuC=WJX_xe~TW5i@a?X|nr{=_o_@-IeiTSq^iBDYv+dIKn!CgDLa6X&YMW^PgER;+@}j z?BPIy2G4bBK7X|Q0RI9q7&R9PJf)$F&Nllb*5d-QEei1TIL#0rbVIIK{C!j3^>U+t z5C7}-2;hHA0VQSDTPx2@#tk^|JDnUgPZe`mLL6eTvF3y(H5)R2#wPz95_3CEf_>>! z>-}xj^vc zgu^k8+=o0rGyJCLV$Wg5T1;v2#G*E zz%v34V~YzAM!+UGHTC|AQz$^Zm^=tN0O3u#6NIQd8yzHz8xZ6GhwML#1_Mp|HV2v#o7SDe*j`uHTpPtiq?;M+v6vEosPzIqGMylZULe*E!1}Z8dX9 zle3f2IxujN!-`UqYN`Api^Jw)?pBEM3k{J{CdUnzwYjDeBlV~MsghmeBbH{lj63b% zY<=5ec&~dCU7wTxrTo~qwF)?@!Q_q?mF5v$;f$F4N{(RPpDbGV7g-@W=??>gN&bSh z0s-^MKTfukdYXcKPz^rXd(P@*8KO{!n&m+mBZBgGoRU%#4TO_LQ2gDPQG&C=8TwD4 zLFoM*3rLs@_|a%6RAkFi=A~6p>#+x&5{5gcj&8X8sm~udx7=|kcil{8DC>6PO=TSE zy{u8&g1=2^8fTs@#8rH+w7ws#^1HAf4(RIQO#Q$@M}Pe}F&U(;NSnllU>sXMgC^ov zITbD;`m%FFe==C)YBBEWue`aCe6`pVh-wm(Z| z$gXjK6z!k&e7~;V692E_6;QhdRnh*fU0Z9*>Vid02jIZDQ4~p1D%qii%m6iKa7Kc* zE7om#6F_~A2Jo+#Xb}RPqnUa(#fdQf-w(zoWfQ@|*~AnGs=%@WzL3+-9R-0cUpHqvUcg zlW;B^930akZ((mdVhRe0e9G@CLJfuLl_|70($o4nId!wJHC)IyqhcbGO8#o%ho$)+ zDBj6XUfQVk!}d1k3}PoM<=uFdc^ws__PCZ2@<^C@-0hRPPLZtN>1Oml+44H|T(BFE zf(cN>DGWF%W+c2n=D3IYA3iVMG$PGAnXxV#R@O@lYG{0n=vmRozaJ{`Kh9>q{LK z$XlN@Q3`LvV({KwVA`C51va*bD!otJxI`UV`g9Lsb`5(1Lk)9vb_)KiM8E?*909;} zFu=rUzAL`~`KWy{+48YM_lyQJ{jziTGS-@v$JyC^l2CvgPFT%fV%21`mGVkLoAm;s z+F^EZ+zA#rV5=^c%p-YKuxjIBj6A0$A7J%bfb!RIchH6Zy)XLTp1U)ZSIo`FLJ-EH zJR){F$v_KV)@tYneSYs6-C)E!IGM@l2?rBcL(armc&pyzAGl=FGb@RDZ6vpHP&`;J zJJ-!W0#HYO2-xiNe$>2#$L1OSNWOmX^F_eR{2DhTI-EkG>^6x?vO=E%iwyVE>nz{o zYLOgu3>3fOp?k+9YMnThQ}@IMH?he?_r)p)@758tnFbmrhHSYWezH51BiGNPF!=s* z^qXteYlJG4QYBt>gc1 zilRnXUZ?#Y0!>N9Ii%{XNXo)T?=~dmTBy>hpZDW(B!kK(cug51F184t92uy;HuK?C%BixsPw9Rl};)wn+{qjOCE_&1FH zvq;p=X&pT+vK1Mw3U3Kv+a~HPRnirwzn@OoM^fO;ACFzx<9~?({ciqq@Gkma^?-0T z46N!wh^(4E$KM>)6dqtH%Sz{Z3B42-c7Z_LKESp29lThP$-1t&?RHoqJkLj0Ft1rj zfyp+FSa`7a4BLjUYP9MnN5=t$@SUj08}{f6uk=W6gCaZ>tG7zPr>ZB-YDaxiU78lI zp+DuzkOvxTducy^i0ZSj1`|s14*M8-hVyO7W?kV(bj^E?y8SZK@yH##-~C>Fj2wXY z36p{=HQiN}W5cLx_Io^oh(IPX2q4o2G`oR+{4Rd{Ab6Db<@`^_Rs7eVnQxR0N))N| z1{Jt>_36x?Zqz7k+@OGszph^MIu<^CZuy0Ima+9yM32XXx|MHp6U{tP&XJPTWuhMz z2jdB=;3MyajtK&Do}@N9i_h2*gWz=udJT~Qu5#`ZZ@MRKc`x8K7hq6_qz{!UPxQk$bkpJRH>~A;ORQ5){4mydg`+bo{*RJ&1 zUZby{2x_1~f{cV4jQT?$;b%h6P?hSE*w)_dHL~{g#PqL1Nbh0>z1NJVc!xsK8GN@L z6m-9|59vFgm)|9?ji9Rcw%u`64%KUY06k|)3Vyd&`fI92YyWRkwcJBd(GEE@xNy-= zN`aSN3ms)rr_sxkmh97fZG(ah?qY)WaB*f6mEyo-bI><5dyODZZ!_D{o?xFm4HR3& z8eAUGIlLmu0i}0;&#AP3%1YP?lL2R*pC=g7Ma`?{-mMXJRwG#RNZ6=l{I;u}c+mQ{ zlj7Ql=EXa?U>-NAb2UA@da-q$K~d4MW~8=Hv)s!l{TE|%tYT5=6<&xUC@WNS?L*^5 z)7S5{_qqh-f32|~?;I6{*?14ejnEXgeR+a-yH`5IWU8~4_!6trEf+NCTIb1JC2Wqt zk3olO2Ds5G@D)~M3?L|d>dS|7u98kVe#0E@bS48@{QQsB6VRKUVY;YSE4b#*B?}@| z*s@|;gd%r4W`lw@_7p19C988CS{qgRJSD98863y#mV|?|I3xa)!~G@*&`cH@sf)XJ zv|-s#De=PpZXSd$Ku*Zj#@|a4L`A1@rv={h4BcjJl^YDXVD2GG8@b2vlSb5Z5hGdj zK5=*#tlK6U>M$abO=Xs*kan))Til_YUs^yg5jhU?L3p)vn}-7Owz6>G?S}tw;jP{U{Ib(J3hS!*7qW(0T}&}B zI~>6_tlKp^Xy#l=YTBKHGfa#K*6}_x<>^V>Q6pZ$>PS zMv8fU;PHVLU`47&^lG8GPSlyybK1jX+4FtH7LqxS9zTP#jBs_MOi>x#v zOhFi(xmK5c;OaDdH2N;jKEDSJPeu_%`I1=iHb9EUN$Ih1pJ(EvV2lJFUX|vIeq705=j zySdjXgEpU8jzxddTH{DwZg%HTf{?U!Mw2!7i9z!d81Ix(uA0~PH1<53G}ywXS18LJR&Al?0aQCKE&@{Sl8 z(+za+i$~i74q7#Hu09*4g+RswhZ$i^!*%U&0OHTdaK@~E8wgLf78<7EQXY5yiBO|Yo0ZWj-sTROA zi&ERUQ=MTe^{*in_6+NH_`lBX{}V=du;?m^-fidqis?#WVyyWRIRCfplQ81HWOe`J z3Ff&Xq#1Z~^)?Qvd{1mmX3sK{G^M2PCW#8#AA)Y@9umodj^UaO=+^(<4u&~|x1_jUa)RK}o`l#-Lv(_t6$ zqVYq>gG1dq@1pH($>ZM~hUf<(Zzk6_J1nk)pHWSNsWl zPtefqXpm)k;1pN24q`z{g7g&1q>&@N&*jlaxvTkeGeH{Q_DtjwEfn z^%Op&cBs?*cQjOgs62RL1kpg?bH|)ZtGS%q0k(lG|r6OXBD4NBM>?$Y16~)RqTBCU1c4>IIC!MqiV3^>g7#)-FYy?YBDEI$? z4@Gj5BEs=cuJ~Y7Qrbi~as&dZ82i{6r6gqu;Jp-cYkYm)5b%41-9B4sO>|FiU{utH zPTE(jrzmlmd(^e?JW*(|@LtJL+P5{kh98G%R;?Ra;740<09vhZ5GY%-*)Z&U{(aa~ zZ_#3XfG)w6(AKhMh>2r5#l06EnjyE^VEL8dtJ5MM#tFN8Hpd+)gg?}Z1(ZDz$tmL+ zC5el)L(UlGF@$vz^Rc~d2Fv7aIuoi1Gly38Lnlj-X6iEuoiB0&Iq*0lWbQj4cRe3! zjPzXmx8!r6_}PfyhO-$#Z^wk>KuJT+$uXXxPPh*9QKO8aj?&KurvsMpq$I?L8PeDO zh_F{xi}#YG4_Lh+%=RaC${re$pE2+7hO#Hw)8+L&M~oP#bN()=^Pa>Hm_)11EC*ve zB80PY>oQ!U=HiU!a|?!JjEm9NYYe9c;i(aI4#Nk|p0xzJ^S>)o-{3VCV{5jP6PaQT zXt5i^IzlRxWi~m^LKVChy%d7Exze!vKy&^mT$iE&Q@P*{5E=LpQI8&~OqGnO^yVyZ zCt}>Oow|*fnN69Q)#c>o8sa(0NfvN{aTOZqV`YD&nj%zgvvi@Cm8UJhd2*cRwq4u` zE;x_x?b|n*wIsDUc|UeTA%TR1GWB|st zT;&2X2e2~>&kB>ufAQ*x5)D(#;=5Eg;+M1>-G%psS4wgm(~XrXr25S& zZY&_Elee)6x=&j6wo2&z2f8OG&gk`qoI+#Z?xL)7eb~n{aoC&byxn&Bc*LGH2`HM-Q(`$oae06kh{D;k#g*YE&F7v zF(*?n$0J@_GyIS6^OmO+n)+pKb&olZdLhd+`*gS&-n}xj++Qk+2xb}5 zY-P@8wHZ;YEi+XH)-&fC#LGy_W6i&M#kDb-9{AGRy!aEd4WOX9ky))4_*u7Y$a2?- z7ao_;SZc1=iiB^Fc0>PBx>lTxQkdQnnuwlu%ogtw>!RMu=J}279>!O@wooR@XcVmxVJLZgeB>h-Vj9O& zQB!$JehEU!p(GL%S}E+|`GJ`H^tr7H;_=jPhK76!=B!amUSdeiF7@^LiKD{aJ zYOMNLqmBA>51CdqD1z_uuvzQJ_}lBSNBza>HKGc%%Ov&dr^=i9a&A+a6Xxe-+Hjfo zX`BwhDWg|krA+T<4ANRFM)lvXEB*FprA^P6>??Hl*lU0vS2~f0CGJ=E_IiWN?%qNm z%gQM*dRY$|E7?&q?z4g})3uD^_Qa;yr#5<>e;aAKZc(cVS~Z1h@wOimZr@qun0 zUo2L8)*4$({&soZ6ItlbdApyp%GGeg_B|#-z?f>*t2wuQ7h58HqH+@Pnl?K6v8;zq z<;!Wqa=H`p#0aeW1!>xpdDPBd@scQ+Wu$^(;16%LQ6*PBgU3Kc)RK?fv?&#<;TZJT zuyGA55Ed|pAh044c!58h9pn)3q<^DeZswPkx2&=jnSO;W>+$`pzi1ls9fnQan6bMPeUR0>^s@6)xswq3l_S_wqozb1$0=?yb=$T;EdQ|A$ zPnB+Z9GRV`7oFS~@h94u+t#j25sN|y8F2W}mW8WNAZ!rhugF-JC6n%xR6EK{>E&mJ zn(i`H2Lf4AtnJy?=+BuwJKY5B_{P``v9lvuBC%O0%qY;g>VwGgmGiFX(?m^RdMp;k zV;naY@X;Vkc&Zb(gaqzIV~jIy|XYnUqF_ywGV)Crt1TBv+;3n8tBnc*0%ih3ZFxauXP>fL%28qp18BTDGmQ1US8vmFB4t1s_Kq_2P+ zcPB2!Oyf^iX4OG!$<-ye(uR8qAwX%?%x?6RePpk#8i3Y?V?W#zbby%c^;D?Lx&|BO-ZXh6N0@`3rMd zTrjT_bEjrDR2M1YMrs-ATR6AikL4_~R?y`Kv+U!7q&`9>dRA$;Bu@rtAUjAP^W#`8 zup}@o%nZwd>>lnIdH>Q{eTeXFKHuy(_CMECl9hzk^fOw|81eY(j>D4M$ltw1@mwwS zo%am>Bul8`x{G2Y9nonzSmr`cf^aTTL z8GaT*`^!OoRL4>4arI}09THGh|3c^sgpCNZc&MNYK_MoZz}`1} z91&T8E**qo*WgGHrLHQswe2E}plFp<%E?WW=E$K4(dwR~5o zU|kr#D*)r;*S&Eu?#_vH@B85CmZK(`^7au!6_6$blw=DK?zq8hdfk-nZTc`=(#&}_*YWT zL7AK85goEa={jyNF7IC*CG<1-$GWQg0B^6Ew39^oWdz07rO_ z#k(8c-75=Ez;|>|0C{628f>6Hf{Xz^5W`{?+cS$iJ#p+W!e<4glIvKsIh4bz@=kT= z>pynseWn_|4K59>nwL0~0s)s;I}(lQEK~ejKAYdW6tT>f2!5AI3>=(BaU+gSPeG{2 z#y0w(R+%5t_+4f0U8*cIvAzWQcF`W$SE%%;?1u%s@kY+thmt;Z5{6Jw^(xj;w(siGfiyvi;pmbo5nY7pf)jrJbFso;=yW7s^owMn3p&GB z=NM0!MawvT+e39dC@7e2~<1zA&D7Fr1|F zaz!j|9{9I}9%Y27`_%9c5Y`s`OhsAJAdG#OU1n@&uIj-!K&u$j!#q{MOk@Cy!Gs}X zG>PuLsvi`&J@ytmY6V#Z|E>37x;TNgc-u{iCZ(CuCpPkw7)y>~i`}q0J@Yj}i2e3n zaJP}QI5$&ml~#wr(Y=djgEhUD<_iZ>U>B)Di4lTk#|mNv*Oo2hHP>SZ$8qWtu7p2c z1mgJv7`|k`Zx@f%9#5XGNl%I~w6V0DKq1}Z%g}BoI}sDG`*)csoMWsZXd$_9djROH z2A;Z52`ylk$y`)r22;FyhRRS(xXWm_j6N`4=IJ!Rp??IH3ArE&?RbYS_c8(9SRhc) zPx41yQhf}fpX3X2uOR9+g)^}T0xTAk^dj8h?||5s-#%bSjshB}M&sQ*I1}!AIV>J$ zf`HP_vvrH;)9LQy7Osq$UZ$U4YzZ<#)sM+Okhx7`=+v$YHIi;q$MblYs#|=7Eq0+r zD~tv2VenKwk4i6h5LBUt+OCUx``)Ry>gZ5EqIgLa6)st4ts6&aVI`%?t{FC~Ve*u~ zAjC!5U8yauqv{-esad%U^~rd+-K-0zDLDKzpF8APw4K`9t%@x?P*@f5-}sUfv7Z#M zt2xJEX5I`zhHzna3C+v zYUvD{FtoyP#W=JG8WIUE&i(U1lcNQ%CM~th@~K79VgZGNhkwPX*im`Sk_d8mArN*0l9LjupFp|96BfM z3`IPDcP67aP5NPb{M)spJg;oWZE`YNiVHrYxV{T={sC)DMq+iHWC41zc)K4huemfy zb|fg)gSKg`D~Jos&`D@y?X@{EQT+%nr&Sl1vi`vJ2w%_*(IM(_n5mBV)&fc?Zd+;n zmcp2d^7!e(C5K9=%Hr%}-JB6it1L66^YEgNNTBv}b9HiVCg+>|UJ+=W!Z@u-Ah?11 z$jX)4BY#Mrg{8*mmP!f`;<(r4?t=CPR)K&Oj^56@NFE9QsG=B2*VO3cf`FjOUqm1? z9V(inP0=Pug}N44sCYdf3gwWLuw5gD{UJm$L)MBZtO|+jdc6*Bc#b%PZG?nD5u5Au zi=QDkjLjT6)4(5z0E?7Zx$-PEolmHLzYJ;F^9vimk(&SoO`5iZjAyNz%|Bcr zb|>I#i{j?Ah%^jl*W@@cG(ENLZ9=`MQob1CGi~A(+44i$_D&oSaL0?~j5qdQ*J* z0PpFVa4&49=`o%}Ap!`jlq97yUomDh%?Bd{Oe96~r_DruVHj|<9n2{qX+fIn*MDbWk3-Qzjhab^AS)1!0p5xB@_x$*sH zQZTUtqs>OI{3IMDa^b1%Ns?> zC?Z!3?;q+n$$WxFTlL^os>1CqH8&mWvpYm*am=0TO)e>h9)`*16HXD?WZ$2qg| zyzwe)Sb$sxjpN4_sL2WLaOygOX&-?XBc@Lg48|IW`qMZWJ$Ls$5yXk4zZ?AFfB{Q> zM(pyWQVT(+a9tSd`Nla<7yOrL7$H~5gBcudZV;ThXQXp(i1r+)gQ>fo z>4z<@RA6FzptY3 zL>MqN3H0*d(!P{KDpWZmTcb^+F#2`g4n}hubB=_m2$j0zn+Gy69^urt_&Q%KQwF&h~i3v%6)v4&|4J%g&{ReQT~;K zrTH5L1P94$_$`z*RzlsJg^rtR0k*nBW$H`F1EQ&T2Ax`lCo$XwajtMLKpcAhS9q)W z;jrAV3-W^(^IQOFU>2JLPEEv=1!9F$G$cpgsUUZ75!*7S_ON!k+JzWXHYZ_gtf}o1 z8BKcV;Wk`aQ5@a5)I4wg(X3PKJa2zYqMql-o7rT*8dg>@#R9w1Pr{ppRMg0UEmEX$ z)H!f=?_T>*^hOazEb&vic`g)p=wPolL#xK^NjlPV1wKOh*SHszYFS;iGi4@Z&75Hl z(&3#p4HL9}xqR9%)xdSuM=m{GoyeAj7vSX*zRReDDOz|jH_fPWAXF>t${lh7&t$yfXQO&P=C9wM) zUuvwrg^YbrZPj8Mi;XA$;Fq&_ii^Ppomat+-+@buUmT=&J)#gTVb)PTV_jgN{uT9o zruFh?1`sjSF(}Za7nw4#(67?kPK7>y+UMIIZnRyUVnjOaoUVHrJDxxQs*KOjMSym5 zo(nY&MD;VomwRXXc>i2|S;Y+h)6FqVw`xDA)!@qOn<-)$tpEd%<<&1xNzo$-O(;+t zpi9@IMlB3+DhK=na#1c};|4XT`Kz9t;`Wg<%pb)NVyZWi4Wcbo{nxj$tpor<)mok3 zZ_@$N*uq=?Cz1YawaPJ(lh#^Ns?h!K?4QN0dGqfm+vqe9VCRhT%*AM=U z+hqJZL+VUOt)@bd;NKir`Pog`9(JOCay6Et2SW-BNc3=e98D|KVx+V{?aM*a!?v*ba)ktg`zV3Hx=~>dUHI zA#Cy3t+U!D8vU(CR*0`9VZsKZ&gh5Xg~YKIiku16{S zdnbv^gG>I)RbK6j09A3YTPz4<8PJb|gM-OebaJNmFbjB5zZSw zp46U)etV}a?VN^+3YcVnh|zK_*XrWls^|M`PPqveCa)LWsV&di#4eiLk11MTfL-p6 z`(!8Ufhr$QCUU!VRkv8Dd}uv1f7_o`Rl^)5x#M8+RY&#(y}+#7T!dVdkY2Mm@bN7z zJrL6BXwd1-XgEHt37@Csx41^9NHfgL}G~=r!i> zxugIk_*AX)37a9>5q~-XP;8&QHAm_Y0imM@$`$Qw`y9Y?0ueAlK|%9d*%3!6sA*ST zq}fL8e~i{2&>4Qc_$y>@X)}7%4N3B+VI~*Hs+%`VhDi1K^M0rP&h-@>72Qp3QRX(- zv1$9(&(s^!RjA%k=8}9d@j_H)EWW0;xY{hf*3b}zCJ2X=iI=|yo?POyw+|R`X3Q6X zG7ichV2K*EwDh#bt!)3mIGQyml7HaA{KsqAsIvVxbo?%v$St8puR7<9go(RYbhjR_B(_&e6lS1K%=ZmrjSUS4Bl>=r1xocvDpI6c+A-R~!*=UI@QPD)l+aovo;M zVUp2-aB;ihMf#Kes18#iX;9!XiuS=SDDpCn9??izcvw0@ejf=QfWnqfu+o9&I*iIs z1+93LwXA_X9B9eNUmaX|)l7*6G$W}%ftWHob(ZgP|I34SrZ`JWg!HL{ixH&xD^9nc z3i%iF@lQ;y+SSj5-9R9Zf?%WwV54vMFLI9?YC3hDTv$LrrBi|0ZK)a2&+$1+eF6g2 z=MldkUr&hj`QoLRPn&fq!x^kU^>d3)Q=N=dy43%-gB9(n8kfXP(d`7!)#M5wK|D@h zn+?P#W1sXeW&G?XHi8kw|28t0d>Y&oBR#x3=hEPGQEkI`ys@P-jX*Ye<_YmMfrRONCe{ zDHZxmsm^Sy`9ZhOE_;$mxkNCvP*y-~wSWzmaesDoMF;~ub)Qjp|I!9qSYtn)T zoZJEFch!q(YW#t8qA#(9qQoIXyQ+?SI|zC{{B|t}Sts(BHTP+P4^jba&;Baz01h=? z#2i8Hf2bvH3*h<92*V^+Zbb2#HujD!*yXe#!1lEn`lL2eovPJg%kd^0WeW$YT`md2mXs*KoY7J9YH6E?))L4DC9G?1W1smf%PrE`k&wz7ON) zh3g$J^u&m$4N<^rZ&~tKkw^#yXrMiuzk=AOf>muhQrL5jUfV#>?jRYA_`#Oe`G1<# z8g0$LWV41=b1^wZ@<+W$ff4`zO2KBSb4}30)cR2@a@4~9S@1#8L`IRDJMDzo2py}&?Cq?2R>XI@bt?DcF>zE@owf2mruUkA!b5A9OHk6v5 zA&A4&E5MubyHZy0F)}NIz3tWLYo)CJvX>e9nhO!dKWA?a=G1P}!C$H?5C!}#AQ(=5 z?oQp0D1zuOVEXTEeb>piCz;bFYAGDqG#m5Y`1bfQBk$lbb}za_^N;5W@ILX608$nO zxTNH7!nEoxe`TCI3e@sViz`oW5+e}M;Uh|)o*A<}v=p^DwkDU1ng$OB5N;@F3uILn zUuEzn4Q2Nhd>*rOnb|2X-{+T#3Q?qaO?q zrUjUWe%LbyJA7nPEo&tssn@N|ua7+?Ixe@(Xu#Lr&!RE<(;(HP+t2p|w6!bmp&lZP zUsLHE`&#ycj!J0PY;_xCBq4ZX;d-;P~9beW5J03p1?g> zj(@$C`yN~@P57%@V`7K*mp#UP5UEUG1DT;!P5Kv}{HRbHfJH=rfcW7#)fa`;zxs{h zCVVfpiqqeBdCjwBm1&!*jb2L5sHm`hO0dIl6nZ%QJ;3EPPb`SvWf4lJIM76+C~fM! zG|3#wj5cD(`Dv=u;Zn1!B5ydR<~~S^QWz2^({vBrD$)f4s!|mE?~WpCn-(`BBA&2a zQXsKFV*svi=rr_w6Xy)n0t*OAu^u|XU>haANT#>oGk%!gX}55A1roqV0bynd|DWzI zfd-(e0Hnx2faEr~QD~`Dz_9=ru5y@MH#yws-dXgiyvf%3anP{hsO~epUZ)Y~JmkL9z-0RX-Ff+T z&S4mx9H_g?(R|dj_>0Y^m89YKX+=z=^PubVbSs#rh!{8T`D9lsZ^NzcMl4?*9C!D! zs;)}yj@l^%;)a{j?s`C6Ab)jgRlxRCrpn=Zu!aOOuYNkY_$WJ+;ayi5}Evb3sq z;-7}7(Pg;G87u##N?Qy8UWY|GyiOW2+X{_HGxn*R0r{N*x}QG@d#08T_I_M^f! zk%B)F+21_N+*#9awLXr9UGwdE+Li#jN*k z6i-w~j^i}@bIG>4$aORp<2YQ<=w@=HzWUN*;1w1>2aDlNk2Pa*h7{3~XaJUOICsLg zDwjeVVZVP?_0uF!e+i)7P6gL4QTBJ}(zlb5$kD5_A6>7`vp}H!f`9g1SEapiBJrGY z%2}X+SKSN@M}xc}7rlv)s+f)GKY5YRvAstipKshu>$_328_#|TaFjz-ZtMVqyj@vw z1kr!ME5GIO&(|mzh@Amy>}EfDBz;XqcD@T}L!p1Dr2yo_KS59lqQEpXJ-cxWeYh__ zyAwX}7Ug|t!(4&n8sD+fiZ08Dikg7TN?EJQ^1|zZ1mnq$$^*$&xIZVfI2{_*PhI zkJ6M29K5A@xYC=dSSv3rNs(c;7saex+ZOgXyX(wT=vP)+!q7e;4a{EZVsy*O#=DB?bKqNc%emJBC-41p5$jiED%4*!exbw;q=>rC`R_S(jUO^NOHP4DDl ztC`zAmtgADi=fU8$_2dF-LivUa%)7BiNNxdE6nV&%-!L`wg6PiDGxMc{S}#*$t(~=L23&e6A&WFD0EKXxMeR2y@d~KQlvhPc)W=x!UmQbZgKsh&hDM(5~!3z0gJXV@r zrn|Up%A2W6QKTl#AwLY58aR->oXyRZ)>9VZe0rfHERzfTN8a|C$(3C&-!6vDsY@a$ zcRB-vN@od)-zw4w$=ZiM{8IRmyy|X2{m4TmoE>e)MV3irg9ve+24VbN!(a0=W|0V+ zF8G!?zPrzcmly@ zAX3Wx=lguUaE+++<=2%aJDq_7Fg!#DAT zISQ9(?!n3f*T$iX$^xioz(cFZuU6IJj}zc!2jJ%%}b$ z0{Ct}A9-Z7006T$T#vv&LAV%HS5=OFcfNTpcC_i2Kc9;}(9&OL9T3oovPaft2Wurp zA^h3K<+9R^02l&FmdLR}5tLlDWoJxt=pm45>-9wcww!`@8rh!C^;>FlA;G|`X0`Qg z=JMVfGqp^SfAeGUjuX+vKcyP$)Y(#W1VG*fp;3|Dd#vnS2_!vY;lPvjmIm zH>mDrF|z1(?G2JG14J;{x{f#_ZWGaIZf}NMNHUCdi?0V9{d@!`!SbwF`%ZXR{Gzbw ziHI+IbrnhkAxN=dDf#?F28Mj_!u7S;C8u+8&>Xy4h=044u(TyXHPXDes2Kg1i<7p| zCFVza-$yC-M?74X_B}OA@1rEJQ(-V8``HXJGeZ%PI~}SiCBoN-yFQMLrcS@kDRJY9 zJ3m~JdCcz9UYl@zbRVTH$NLU!G*Af=S)QdW6F*p^69^MG*$OWH)U?(SM~$fQ(Xb<;Q;KJ} zk;cU*O7Xd;f59#so}oAh6Id)_D(of!f;dGZ<8&h01z~)YhJqqa&ui{qDOLTmrxj>qhaAmO6DLr1D!is`}NKzY@gn1XZ4*&?4M3U z+WBVK>Z3&KHr?V;<@9E*2gkD~+=cS1AkKY@rT?qJ8$b(qS}`G+4tdWV~ZZvt35zp-y> zPJu~af7AP|izsPH`AV9HK-X=v5BTOc9UOTkwZPgF$$gFZxr7_r>S)!(V7)HWUm-A0 z<)|~pTsbqmEJj?+-nvVjj44m^rzf5{ zJMG=7&Q{{67WHQ?h8xf24}{Y1`7QD(Z8`SqX7T&Y*ZrPFbL87W1odYpqui3NZXU&n zlTc_t(a@^5g;$!?vVblT8%~sXKJZtb=|OnRH3P%nXQ7I7GfkE|-ZL~El=Yoboe--I z&Hz=jyP#o39b`R7J6o9ty_U`cM9&oLP!UDpQas$kFpg-X})L z>zmX_70PNzmhcXYy;`qn$4ACE*%c78A8KHT8=Xe?f{Juzzp-*;yT;L9X;rrRQ(oyM zWUVD)FuL1ZV4pdds29Nz4er2@k8kjNIVWWUtkf@`G!2C@5cB^Ew$Tng<0|G8fbHog zCoBBibnG(cSJA=h1_e7EZUlIUef6GM-Rw+$Ly-K1M;9WQFU|8lEpXCi&xO#g3nQ?h z86vxY;h*CVSpENv7X7clYO8;VfZ<^}pIggMWdDCC;&L8c_pz*eWO1?Xl91;12hdE0 z_|C&hbmSKdoTfRnv^8j-t2G=kd&$4@b^@q>v#!M!Tfj4}p;Iu@WX~(w0L;x_3yiC4w#r#2>Se$l(sor<%)6iI3POy!5 zcFw?Yg31RoVp0$g&p;_EnfRoV!E~EG6^edL4i|sfj4#$J6~BQ$uJ1e}94_K6Kxe#5 zMq^6usg-p|J)@M7NOq<|kozi0XSL=BYElIha{|5#T%5Ylnl{aX7MZ_CCo>b zT?f(ekmh~8)eG!ogprXuV-lB2O-U_TNmvz;*p1cT^Mms*6%CjmBD}z=%POE!7zx^t__n2~8 za~saXVVn@n`gh|3xlu6dl2DG3yBrIq?0!Cyw$-=~ogmPpbkzkl+I-h~7w4b!@ZwPm zZ0@DYwDfA@!nC7_YFk#5*`CU=l;rB%4R7C}XA3LJ7N!!It@=W~*0R^i8xK2p_vLq7 zv}`s3)G;vG1m4N}{j5Cuw?!jgZ8khBPaVFfU%s|*jbS{*h1w?V+Dxr;()?QNSiAQ) zOS->Xr@aY2S`#9ND>Hz=t{I`RM*`wggkZAQ-t7yKq||ArnLhN&fO7jtF>c(tIyWO zFO~=xM!ygPfJs?tLE3Y@O`Y#!!mV-f=3Us4?(BR zdQ^-g#PW9_V?)}=93TBeM)2rUfhH((wUNbks)qWxbC$O+KOJMV?O&gh1uH&Mq@8JS zEs3~Y;aZ};6lNN}5f}S6nt*>C54-N6(GX@tWo%Aatl4Q0o;ED^%EqA8AS;|AQ>dnr z(f$J5k4_d9lnk0Ncr`X)iNA&kCp4#3p-M`u>t_AUlLlA{r0GvWUrszCfjYx*N^JJq zB;B0irbOqzDzhqCowbg&mE@>f@tMGR@Y%tWD-_##=dxBg?GH>eJA9S20;>>MSKLfRvz9D9Z`LlYyg}iLweQdneYFSFcvGJ7>gMMEd zn_k-74zq)Ki)({l)vU?4(;+(eXcjw|Cmh1YZ(~konw5%k3#FgVL0gZmpd$4>kQdCQ zk9%t1$9Qma06y)-w!#t!sNtwq8PMd*X+qeXjzeix2{tOkGN)z;!F*B_imQq|i8 zi|oC_ugw6N$i)C2gq~xb?!j`GFZLlAkYHlAzsBXRres2lY3otC@2*yKg8>%f z6zhwVKKh*?TumwI9C=W}M$?J8PuxFX71WZ3(8?(kNmpvCmu=!@2q=l6=gL_Ee-Gp8 zKIF`58k8}pU({bnJH|*=RQ6{l(DNp)61ZFpyud~4esCy%yn8)ZnhH4Ri&tVA;wP!j zE*$Q5?@7S&ake4=pQ$B;$VN&=Pi8bv#xV{J4GiUeYRscLg%;IKJdly!K#K~+C_iTW zjk=DhTrnJtYQa-4FFR}Tf*L4+Iv>0>3`0rBZ`Io`d9ii!UNhxQLOR@FO6Ed#MN9h9 zLh2#RJ=`a^92=b;d^P_w>uT(qDf=5#GK{mP!@-7?(HClW`yg6cPi+KO_p9ZD!P?)H zmnBuN$_ zQeY6_;rDGlmy-6%mG8KkrgvupD_n|DbEG;=w#}~d8|@XH4T*J;6`5^6zKrPAe8!4U z^<2_rRZdr-4@QOvo)Sl<#|g5`eyJf)E7m7jTV{%{r04FdLu z2^kp~2(LZn-28!A&k6i3x#0U1_St40*H7W^yTxc47if@QWcBKDST|ZNsV9k5qIKbH zMDfRGsFAgO78`fBXfgS~_iY~ZB3%}P_OTc!8I#k~SHH_bnt{A(kc43N;JxdOnP&b@ zf7mub35LiD(j!q7j&E=Zt=Xk=JS-Hi3PD{m=M04fE?Qi6dCiH3dEg zt%F_q94dF#B-+LA)@~zV+?{~pH9{OkrKn5-sK{2#!!jr=+~9RN=o{$oRW1G(3q}%_ z9@jI-X&sI9GhgfF!L3yDqG0xzKw7n}nG1NZUta9fuv=*Qa3UN7nr#HQLVfOZikK^* zSoa{|!eIYQio83{v6@9^pi||qX#SvWz&e$O4E<6BUvR14)8Fj%g3>z|?JSxRq3UlE zk1{(?RGa#c(S~B*;HzOK-%}STt*4d(Ib+x#hoeqarl( zl|^saxrHdx6Q`MP@`e5izdMw~7j6&sW+u1iqo4L6+Oh+r?=ZHLm~n5rKQO$W8^6{6 z^S+0koFbrs%MTMUynX!$k_*+_?^~lKJz2d&j8uveU$^6I7&b&iS0F&IZ`4Md8W3q7 zeUnc~_bY`MQ|gb$00#lQ9v@JZq`HEv0TJZhPZ11e2y8NZ37A_VBJP9Wm0Z4W1l#w)| zYN*(667tvr_FEw33=Ee3@0J>q7Jp{Y#lZ7GQ#>SmtuQii!?y0v>jAfNR}n^y4LX}F zsEEfS^dWG75lnrvo&22h7o4Am=)>l>u{yY1IB*mZqdTyHByf}4^lEO*lF>?GT#6h7 zfjo}tv=U?lJdJ$QholU4YU2C}xT3>dhe5612tr1LOV}ptNbc;H7v?RO7M2`rb)_Zh zeMB$kyPJPy<~ic2V?wpgkK%8JA1ULDF{^0T3(cFTvVY*ljr}q+C5Ma%;S*TWdS|B> z@s(8O6yBUu-WY?^iioaEEoG@KYRdOB0YDlj{unNOSKX1Nn-61Wp8r#$sy7sRptb?0m6&v zL6>yu7l=EHbOMNO2!mxFMs2yk%*|9h_L>Xv#~WA83+=ef-}-J@n@~3FOByfl(u`EMy@Z(TDP1 z47%XG&(6rfK!44T=>$T?O{`P0(~BTX;S^^nt}4tB<)eyBhDAn>t&WrJm&cKf*zIha zvP96Y&K>G5c{aDpO9^~3C6}XFNZ6eRTEBN6E8aAvABKPbN&LY{sG4$=ItGm_XTX&t zH|hCe-50yxS7a%{`mv-LIkGvS+pp({27t>kkOR$+d`j%b&J zku=~t%ri7C+gTj;lkS^IoZ=W&bDT^nzwMWRb9 zr%L?tSQFRU9li8?(Y7?Bbd$#2ZAC}=c|hh15N0b9BbTSUE1DfP9kJ=cXqQ^m3)z#; z;#V$)8>+*DqFM7?erQe{mV+ypk=6adCD`;%eJ z^Wa1TyeuvF_X6gCYo3m*-d+bkRmH}}?sxJKL%t%o@*S2b_n{6dy>pdD*+;$MJeNSb7UU=_} z5G-*0HOf%s!jP#7nsJc*&|iB$VRPeBF$pcP;JUdYEB)t2{@ty8obu`BjGGGH(~jnf zqD|AOm`d<=Q?vxZz-0K2OzJv4q}_uG&`gS{AtFkFay!nyAdt%%&2TVxa~-CU82_(F z?w5{4bNRakpE__Pd#;-c7rU}3V$7mtLI?>w94(!XCQ1$-8|okX?Mt6*#L>Gp%J-<63piIyzC7L9_-@6nQHc)L{THMkbIr=S* zXtO66w{`w<2|usbRNfhHSuJZt!A>iM-X{M+bFWPJeCYyemoML<(n%&n;qdl!1Z(eZ zz+SlwC(!QakyBHF)K&jxx@{f7gGKy|@Ebn)Z1w`ip}yAp(CNtj-Ue^*Dzc^i65&xC zVQ_En9lRUMTg5l^lj&#zY_bB+dihn17n_djQoITYVgR`i@H>p0sIW@D{eHUK=}+@# zW`clo6GaCc(eL+Q+0Cw_1QFAGNinHE(=d6arNIc(4=_!!@pQg1XB4Id4Z|A>+OWfJ zi#V>d1j%lX(z9#G-?zdW@e3Q7q1?qBAbj>qU%s84;V7B~U|JS?$q>7L1BbNFVw2q@ z%Xdv~|9Ma40ySjxo$Pw(z_B?Cz+WpM0$k`Iqy~w@m%B6VNG#&E&!|^2?CF;B;{y+^ znxkq8z{8;5h>^kUt6a=o3kJNo%s!zuR`=~AnT-vE@OrCW+MxM4bdLz^4}(*f5c_9a zlpgQEeP5=l<}P?eFQRO3fGSo^mQ`3UO*>?&NqveU#(5|_G5eHnj zqNhy?JB33C+!3rR7K~Z-K-@o!cO?>&u?$qKnT-@XmL~c?d4j5=zr;p0AfUNVhqXBl z`>~?2-gRi6H4#>PO+N1B{MjVr5Y>zF{Gc?lKM&~s zfksj>n>%|ncD}XXQ$rLdxs%v7k=%x*I0AW1+Cz`N>c^7M@fBgNjPeIm?s=-T8xqBd zzYk2R?`?Q$#|ost!I}HgV$DnE7K_uLgi=FMT&w;9ii*rZs$c20@I5WV17>f+MN`S- zvW1Are5PIiE&UG#dBq*9D{T8kC$0Zo)aG=>sqNHJm@c}zA zdD+%AanW^kzxj?J&?685dV1sBh2s-ez08i(um+NJcdhs+em8A~#-~sW=65s96sQB+ zw{qFp{Jo`Qeh&nMZlL-c=`B2Nwj#0$!RZ!8vJZc$Z5&;OS}PdwfMCc)8qGf6^2+wW zCU8(Pz|6ctN00|$f0p5?f+joR0o+FS$F$6#vpg*Kp2`-TXiKa|{6{+pdT=ZZrTmMA zzG38&g63YZw0R8QLS^GzcEx3BbVsgo_Sd>!)kC)ksM+TP-sffqKE+v+Mr-vc`IcS5 zzksVkx9O1oO^^CpG1B@Ol`02mqHfER)$w?lx+S{DEXG>DeSEQi1itZW&2F&%8Rpbd zdUF>q3%hqb;x8Uh^5V)P;1J480uaEs#h9+BBKrX}gnYKb;U3i9OV{5vL9IW3+G?yi z`y-Rw``PsseIr7|mGAw5%A0GGM;dH4#5ADcPk@3X%@81RP6um2Xsk!A+r2x@ots;G zkXZSyAL(0axWg{P{!#g|lKy>f+9$9W(3%icN3nG-V#Pwz!E>FQb#JbfqSUff&P!d^ z!mxB#zGGX#Mpkm?`kkSp41%}NQ-=Rb(`9q)(lvA3elgx7pP00ZSm;J@j&nw8`kf@0 zGz`>W0~)Az6JMZ{?_CG(@)g?XXHKNv_>${+fM+p&bZK*A3jkdS7^1tcBLsF1_;4eX+`ZjPy z5bzPfnmhnT7X1%C`#GI;f-WyHupe2CInn{8{46~n;u4T%lf1(K9G; zeaRR%q20WSj~YvR@eiU}jn?ReuCb##xPH`}%BC>XT8#OLn=B^SNVos2_&BbE!$Jn5 z2{_>seyLV+TR79{`TuS4(gZAC9PQzsGCztzTg;+0MZR7v)D85gTDb%uDK1^z$z?sT zrvHzzcZ{*L>%wl!wr$&8w$-IBTV1wo+qP}nwr$(4uljkvlaurB{MlLA$xc?XbKjY3 zu4|6LkNm&4ngOK7)JMyi`c2Bcc7 zy|}e0f&L4-|1!tVV7;fjL8#{-}hydzuqX(ZdDfmHzvu05I%4 zEDPlRKS{#=>yd*F!BVQTEaM;DPCWIMuj#I*7<4E7zmofZ`Ivv7Kmb1D%g`Oa073qr zp6dSv!RY=-8vbAHTQSPDj4~DCPd2C!NIj9h1f`7Q|1#g8(;=Emakr;ghWvFXWs!6)=F<8i7DOjnhso{WEdH58^4hHL1Zc2s zxQ&#WaPG1Jkt96O>ns)XPZb1H{gq}i8tDbdKTIK9wxH~=+;4-6w4)-6F;J|yP7$#6 z>&VI)$`N^XLc~%kwNBvEcz+C>-S1|{x{PQzDL5?9A)bvR^nskS|Jk zK%B#^h!?vy%+LC7)Ys-~wxRie|5k_G->%ZXd3YHQW^D!&>}v9y-(`Jg-+eHn_GCtb zT+mOMN;-Y0+DG9Vlf)AnR5_6G((dt3r730WQjv3a6@HdTtE+z?lkj+@g!}~kfAgQ~c|D?@C!GE?;PjV3RN4oZ9B9NH5 z8a_I0dwGy`4>T;(IsAu~%pXod8v%9%jx{X>q^~hW;m#)HbXe{h9_`8{#zO#>H*?ka zhyq`Zi0~=zwbR_DV0rGin6c2WtbqmsHHRaoa8ocdxH{070!_Nith+i@bFiF5^)T~A%iZw#cnuAYa3!n$Q6N`EPkjWmbDDC+haCkc`aNzHVJ zbZ>39G<)q_{};4V*93Q~0`kGJxvA|D@-tzX!iee9;q`3`ztG&eQLUH1*LY38(BI1x zuVvPlOD@$t2J}EUl}(!`BU_OZ+1-=_;V2ck(%5fLOA z2SA*gF$jb|lPn4^R}6{#)iFO)*ufy8F?wOa2j>;M;56ylrxqC$3T-BuVz1}iciF?9 z)1oDm7hoc-H?4@fj%B!|He?Ik7`oT;X_1CS`61!6<3O!$vVYdvI9Z-Vdcvp-T}-yS zglVr2EyXuWyA=8)8XArYl{I0+Vdh0({Iye*Sr0pdfN3^G!#6}f=sND$u5S80?t|DT zt3Q`#(JMO(OUAp|SfQZl6M*z=mJj=l&?_a(_jCFUlUC~|sZAmH=hp9z*P6OQ^FO|+ zT-1}uC5@bEbWQ$%y06s-lVF`Q?lLtwnEu5o%-Z$)qThwi+V?g%o;+|~dHeGfHEWG& zTTq9)d!|nA+tMmzVoPf~{2=)O_4lPj7()c!lh<;{fh`pAC z#Cn`S@bZY^{I}q`D3b4D+Q8vz(PXH0hdNNX-Z!j&hdue6`KH2Ce8n>1%cE(tw|&e834X%lAL*DBE#wk}dNBs{_OWyO`5;I<2#2v3 zyvFE{jKpUVKmC%_GM&@*f=50& z!P0=g^Pt~NB=`YlHy=r4I{|#EYpgbz1435Hd9e6l>$`-({~Yr|UEFlc^4(i$`LnEr zsr5qVsJw?i72j9n6|=c4qo$MXle(N^c>}nGk!(d7Q#txIb5*@XJ?0|cL`uO*S(p-o z4ppRvqgmh*!2qQ|2w&vlA==hyq(Kx8{BLo|lq$`&*p}sJKmO@5TbM0b ze%a47G*DO~S}?(7y#2s{Lyu<78U=|jkq#nLESZ&67!FQxINPmO!I$lBrMRCM*0>Q4 z3{+AV&L1qG<-mv;Ac2&-MJ3_E^xIRdBZ;rD9m^15*FpT&`8JCAlTkwCU_xcq$z+*eiRiln5_>guId}t5u|v*;RgY2i-V*EIRc}r_(C1 ztoe%BJPxI#U=_w-L$s+i@YtN|+iJ;c>$zNR9k$N{vyVU%{JO5F@yTv}nSK+1m*2@z2M zf_H(0WFk7{75B>&U*zez)5b<8nn}zpu841-DSS+m?orx^P(dmX<)G|B>5=qW?9q~bgi{7);h+3Leo;uo>AZ*eY+6KIK zG97-l!95izcT)xx(KIP_nQq~n=3rWYSn7sHK0n_xd2s9T zd*dcbk?~}^+0I=1FkIV$FL3n{US=f=L!Qb0F-Z9of+9F@nL`|kURDKt7I@1OZIHqm zd0Mjei@QfVFpYLpRnE6ZVG#%TeCL*C|KVB=!lBGi=Z){seJH?~u30t`7Cvcxj}zF(8;X*CY)iN>jVzP1XK9+$h{VZL zA7={B!i9XW7<(3tf*8!qUE`7$P4Pi1%HrK%5)k^?805XvGe_F1EHRN~qzslSgI+92 zZxCyhf~#W~?4?Fy2foqED1zR-llk5ILe!IW{>76ja!sTu-5iz09w0`#X)wPgIGcKL zw<_fjHPDi8eGs*CklhyMmF0pS5x{W7nG2FNwa9r$aED^jMG{x-sw;puLUrrO&(UJf z@@m&BR&_J_M8Z3WmuFZKtfo(e$n)>s3?kx&`WaR^=3+8&&kmh3MzjQBaUkw3ai9p+ zI@2YpAypov2Mr+Y8_O4QTHh1iaW39;HCvb?S`x@{<@jis;|TUdhii&i z8@A=6&K6JYO@gbN0Q8RehZ=2WQf8}+iH_Izi8gfig^Re5)+XKWFw*Dtt>!uy{rFBs ziT?KUU?pA*Q|YdBT_Rr;)XrQYJL$?r%m|soC_Pa7T<#V6K)QDo7Cau%Q-3-#Au3zm z2z^S;!AY@d_R-?HB2|b_Ws{5u40g33g9rws^0@R6%>4sP93}uZJlCt$8og7an=re5R{jyP-Qbh` z;snp=Rd}e%?Cuq7GVdh~?{7vGJm}FdGp1%adi@NgG#~D`A-ipI{-~fNqUD6)4@4c7B$Cbjsm_-~&|qs^lD*Ut*=(~^-zo2)WfnH`(R3Gj&G%kP||5buq%%2GPFN@=|3)m!Pw<43p%ca>7P%J3~YuUfWTR6iLgHWgfy3FENB4yIatRox&hn2MNLDoE2{XR z&aepr{HlO9w%KjPg_DX+1!f-If@WFzXINy+69bh8O$-5K$_v}iHT$mC-PJWLD8~Ot z9QldMp!*R_Y(*6}seE?l{NS_raL+-OTfhV4c04zG({>s@Tz#ghJs*-p01WBZJqkmC z&9w5_!Yhvq^o+UGt39whjCh@e$=6#vtj@A4SjO${xw_trtINNqKkDg6D(i;5xn$I& z99O#EHlU!FoFWF{GekuzN~B0NPnIvC_J*0qs}SIT

l?s7}*4vp!2W|88=L^r| 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

nR1?qM=|aYy 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

F}woT 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"bt0}@AlIHaMn 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 literal 0 HcmV?d00001 diff --git a/docs/build/html/_static/css/fonts/lato-bold.woff2 b/docs/build/html/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..bb195043cfc07fa52741c6144d7378b5ba8be4c5 GIT binary patch literal 184912 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

x{o9f|7gEmo2*wv z?7&s&_B`qFUY>GLIw{v9To*&gMh;QhE+?bNPT0R?7!`WA618s`CAQKeiO`;^lCE7l zbz3bz(~KSUi0*_@EX5E7Q;9_AOU#0)g9SQJMW>@d zY+IpgICVmz?J?Un@WIW;+paH$Ls6Yy9uVS(MLkv>KF4lK$zKvam&_6Or)9Bl>emu$ z428RkeA!X%k@vI69SslFI?qfJmKfenq(ge{M5n_The>b{Z^oS#cE~}Sgke5ja@QI9G z8|1I34v{mkaQWgI?n>CBQb7qfL_bflb>64hs0?jpaU)4;6KgCw{nY?l&!%o58h!zb z<1V8idvq$r0=jqd5KoQUPec-UMPga8R!HR)41iOG-E)<*`G9nnqE z;EX_&2+!w_gjL^*7V~Npl$dke48^=V09mo-!N|(Nfcd_~zMcrcI{L5#e%v_eTZkc~ z$j)BqhI!a%a(rJY%i|sAz9WX^uPR)1(y^v`H4QaOad5AMcG6my*LWFHHl^0NDE$cH zQ3iPx<{C7trrDrJxg@YqAkD2nCF@+5RH9NT6x`HqXM{+aXFze7kR29dS4;#BDR=aA zM``BZjj@FhtZB+iQY?l$A3TrtI_hq@E-Fzu6IsmxjXg~;eP+6!y-~qJO1d+B9irr|Anq{O&h2Fw zUj_S7xKJj~9Or++bbEV;xlZx`nWx={GcO*l&My%%GIZek^2$Vm%hInpzySYatsGL5 z@?zK!hpSn2DI>%IVS*I`8YJtw4aeKeuhZe{QXEGom};$;NZ|^cP8vmwT<~UJXqqb& zNPx$eo*Qc*%`Mu|(Zk3ffHv_4`pGbH@l1rUH<562Cg5g)@L8|VE3iOnVCD>4z(hwDq@Aab5vNFQoWCs9pgJRajQ zdfvPHC4PZa5L-4-gkhM+>#2Yyzqk!&BMOrJ96>wEZ*|xMqVFow%+o7_w;TbOsth8- z{xIc!i92<|ksx-j-^N12(SVf$Ernf1P{?wlc*zbHDV&v~bdO|z`D$CTGE_Diy)nW#YC|7$+eEyl z>mI-D*z?ez!b8|uKhqTGIcXh4jOJmIjsSalr>4}xeO#3-?6=V)@tJWicKfXBt1vr~ z@-M(+P0r@Mos3Y{BxQv8m7{X!NrcfE508imh%Z6hH`(+$q8JV91;qG)HU-0p?zhSH zR}&EX0p#?<>0Tmtqaat9naqi2=n&13pMw+5I4-jGET+?&eZFSQTwZ?c+~$>b6&RZk zy9#|~%pPblsnJgPSPFw~j%;|uZWYV<^YfmS1=P1T^7nk+?-Hs;NsigEP8=a-7spzj zll(w4386N}<7S6^GdM2d{4&zVV?Ewu!=0uqtk3v#T*JHhgz{b!IwbTmF|U<+mC?!l zNJKfwoQ>u|JK7+ka$HMJv1vl|cz7ri6jj9;yIni#he!EK3xBui%ns8=vpj*zpNhQ9 zJVv;-@WVNp@@&uNv?TVaV;v5SDdioD_SzjB7sLi>50Kbpj%vYgXbr(qSBWXqUDZ^i z$^~_CQ+%+?Tyn* zMaz1gquS}L15xs!g4J6_m*qW3m0powcuGF&mW;Ph!)4+$$wCq5!q^; zSwJWdtwi*vGUObe%!ehjr4M*a6i(DLFsYaR9r~D4A|W4@p6(g;9J=4$^OX^l|&{(g=Fc?IuTy z$i4=SNQnvgvFndhq`&o;3WnTEh(JoiUL`@+x#rcRxbuhp&b=y`*4t!t+V6Kf)B^1x z7t4|gaC*stWQ)DISIIQAJ-SbOGerwh_0`zFtRN( zp~U`RnqFNz8W5myIOoV;%Def28=V!S!2FYjwPFmyC)RZz`B~}C5UVuL1Rx;`u%IZA z4+7IePhn@{LrEP8ozz3FPCg1niYGPfi*L)h1oj6pIO77hMaQPzBpjB3fxJ|Nxc5C8 zM2Pqhfh9KgX4M-IEyE+@ct--0l^d589|z}>GuGIwE9d$vZL8?S#foiHsqkV*{kEEj zZId((k|uCz*Bqvh^Gn3sC?*AL8;RmoNyp}AC9wo;p?g=AkJ{TEDI-~Za;N?rDGCiJ80 z#Q=;RF;pJSeXzC<(Z0@JFGvIu*ECJB8Dp4KX+iOR;4Q6*eS?Hrl~U;`eeMO?d@Yj2 z8p|YdN_nDs==*8vrL2}G=ylVAucdB&&W8Nz`|!5?>2@+De~1R6>H5f#n4^QuP~zP- z{`%bILg*W7{X;9Gq0z;P%J@Fkfk!L!YoG$WJ-RzC6wHl_tF)?56H4Y9BB+Mlp3l;- zlq?H#42oHQmH2`!W3dePNmZlaPD$HEP|3XDLBgERniw}gE}4h2iO=%LF(4k3o~Fnl znL5WM7Pe}R%2xYK8H#meF^H}SQ~Ev8z6pXTk&(Vs7QPUZN1=j|BMBu*sw)4O7o)}7 zQHqURjnDE3LY`3v7s^G^02wFDkz$7`vEQ=QW?r>ar!N`lfi`iBz5)(nBEfJ;!MBEB z|HwB^6Su@P-=;AorwA~}Pjo%dQiiLZwnfIAXXfnTtbSXR=Mvd0_Mw&Qk#@HF44$iB z!kA0ae>qFo4Y&cfpz_ksHhxOLR_6S$u`L>}{1(J7w8N9a7MD+2<6S*umhOx?mco<5 z4580~N@)OM5ofifNER}VD)-`K1kKFkBePhaA-G1uH3%=7q1zS*`@2i_B5U34o3twx zm8x=|r=?7gC`@riaVq?`k@ORg{x9B0N=a%BnHO8nO6#E%&@$hqYEEWIbU=cvuFzJXsYOD-+OL@XH|I+OIi@f}NJrQ=&3j#K^#3 zLRpY}?JvdfMFxq+i1y4vJ*L?wq3G1HPqh5)V!^I`;obY=gI`eI2uWSk%6}OKv!q^9 z78=4@?$G%RpOyofDXlu$y30(iq6AhfuH zqd!mm^CS{qWTg+>#alta zyot0tZtf}SpofZ03_wn!#xBQU=#Lgv$F&uqITMPVI0qqkQpxQ9q}kPD2Fwcs>mL7~-;ug&rgneG^R8MTpePS(MkW4&;k;Y3onw@O>NvmmGkD4#9!xO~yjE1E(s=V2{}{8{QzhxQfk8FpqCmd|DKzV^2GZ`d zuFl18AP=!}@^QLkyCTy(CdYf^UgmuYOE3GNk&jMrkOIEw`QRH@ue zS*@Bpd+E0hnw&4NcpR>8;#b)_F%3lEk+d_^qg%HPTu znB8W#o&$vTlSRP}g6-XTuAsZbcYs`7SluI-^LU4XtkaA3vbn=ikaaIpd z7o?%rQb02g2)w^!SzmHqYNJ*?%VEQ8MKr2QHLCzUK*GOAqcnfMel(8SlSV8doJ-Qd zk9Rq4h?x!$k}3iV>9CLisr|B$NXqP5fq8%AY!t1{0NuK^4bGAsByNqoWNC-}OI9Fk zJ1C_)rMxxC{Wm+3zcPzNa*rg2Bp7ntKPd+9g+*c+$;t#Su9Msa7R;KLoGcAxG?5&^K=#kG&Z3&0i5G3@7ItzLhX{Y8h3_?HOL;tl3XBUXH_e; zw6^_((WG@MFMC9iyV|s@Q7-oW%K{j0lf1$z5k3I)0Xe4`f`Q!CKrxE*x+sm)3Hw(DK`%sELtU~(k1^VILd{S0fOp{g&rwR~U?9XpY$YrTS zLS>A57Ge}@_Oyk$Tlw5EDqN_mq+2(O=18$1CPc1lt+z++U|}!eGoaAmc7Ly8H+oYo zE|RMOP)F!}R%EB{FB~=(}Rw#*h^`UTwxCL4_Y__bMx=!E;N>r#Skwy|P z=}MdZZJo*Kmjs2aEXuP>jsy~W#pU@em5x&9aLPRy^b(1Mp~@-E%5c)0-~(m9NoR%I z`^)>3U4oMCoxR+_jcc?h3)$NHxHOct3{JFVWr16tIA$lQ>XZ8{3EX%gu^R)w}iPHg_Htle)QSfBt4Tpozs#^r(m{cSIsiRBXz`m!RH z>c$_~oIiUi*#s-I#znN(aW7Y(p%s4)dT5i};#5^w!y8Rd(bSILS&|@aQoRqRtEc$= zIpk`90Db-p1y%uxRI7)#NOK2dkHni1wALRpGA%j&^+0Ixp=xWvX2JDa1({Ue`yxCB< z-ikxOd0%)gp|rPytHg!~%ouJs8+%qoJ29>PpypG?k5AvXhMce{Is z=(4eIuf?*Xz*`kWQciTnO*K$#k??D@shtoH!K^?RCxc@0R(LSqoV*#l7prr#2YF=u zb&l|*Ia3g!PE|n~EfAU)?dI(>F?TD;`TUdoihaP_f>^$RHoGwM_6|L&Tm53uY&$Yu zZMV^!gO@ROFK3f#&dcfTLP0mB_O&$?PB6KF()eK}QB5k@8MW6FYc?-q|HccuPh{~PbOZw6KyNL38jKQb(b_&dXfSc#|$YTf7Ogu~o&)Gs2GnX@reRoRtV zv{bXkLiR`;rg1m3}6h|!S()J`e^$apYizZT<$96gT?#X`Osv2dXn z!iSI2S7~_(yc+eex0%2zAhQM5ibUzSXdY2 z7@F*uSbHqFDW?(~-r!^nh<&AqCqNfp)1CrB*6WYcVWD>ZNhQ#_XWZ1sH*_kJ))Q(Z zwa?YeqOe|(?jpUdO*}=?amon3Hx%8`v%nHBVeG*gJo-_i)NF0>DAvWeP|Z#Ik4I}^ zoG$5gt+Fy)gYfyv72~_BWoL|t%Iv-r+cXSOjIURXoThjiN!aDk#_t#P!CuX;cZx+v zQ}KE@T(v;Cz>@A$|3A$eq}C|n`uGlXaN=q%c02)@zr>N|)~kxPZ}w)n8y~MclEzdB ziL+}t1fn*1XI?2IHtZrxR_?%HB_?k64#S>?l)W7Wh?Te6Q0PYVXv~qcWRh3@Iuy^5 zd=NfE+IGMje!_=>%Jb^2029_k2ns!YD|eSk47lvuRoXkBvZ+Suk`VvM9?Y=!p^BqC zLZEE#B4)Ozz6&V_K}Eeq5N)2m^`(i&61LmKo=$}1EPagmsDI-J?2J)UN|u3)59oYJ zPzaaD&rZLTNLC@15h53pFMc$CH`5oIe=YKxU-MVZUlw^U|2fS!izkljytt?D`fcLd zzg;EoRi$glN|dk?`ezXzH`SqM^$00>rf>wqX{-Z%t!&c}OE!1^+k3tBKtk3{pG4$> z2ugNt1XYV*>ORMhH5>V&nyy3OpO#e0YRV`eNwSW}`8n-iij5!JyPh%*gvYIt0Ef&t zhwv>rTTls4!X+EGF3!j~L^pv3X??}(Y%4H_5B*b$qNtS9z+#f8r&G8-M!#SRGUheE4*i*`)JwH5 zWvR#7V+BYvIH5P$ag{+sB94S`Al>dm=wwIcC*RJC)kp!*L zF;`6b%3$P8d&v5AMA0$E5=`eu_Zhbv2qoM$d*gZXL8@>hkIGq#yBK)v5B$g!Vf6C- zrPGM{hnUw+FB*D?>y2QPM-d8JfTY>B7rPitXLRagGDwCRF3U3*OZr(%QVw@D2SotMY=jVA3yrQ2I6hu6Zdd z@^8gA8HE+MCpgOH@7QTG^Dy}+y`LhCkfQ-;`4FUETpNXkgHH%tljxPHmHM;Rob~_n z)nEQ+s#@k4pxZ>G$$X&}s<4`3a;mng`Ty59|CiBi>Ob%;tR#^P{uSXj<`Vji!};FW ziAHE-MQ(QAvrIQXtN#SDdG|L%S371BR*yqS6zfB|tsJ)8iJbR21mXFt!v!aiJ-}N> z1(}!}xz-dxNs5JtWUPNwejhN`<#79-_dU<5y-09WZXT)5d-8y`9NTrg7GB-#N=KBsI@7w6`MLbMjt$ zcMzFgfRL>ghB063VVk@*#9{Jf?8W}?)p4+|9^A*C3ES55MmBUz+wKe*QjNwV&=)d# zID4|VrGELxlOh0hN@RjX(p(Q?g}~!bhdH*s$8^Knrzb`@CryvD(_Y*mtDXX3xd&E@<^NbF zvwMxPj3R-;+Q}vF0C?60n3TxuuAts)?Kw@KH)C(b7uBI+#p38bBSjsm*`kuo^c}RM zCw-D0{&Kup|1%)gvn(9WqUmgCaew%){m{dQQLutsuoLvEZHjXK*i|Y&KHS7raiCaf z%-1zut$YelsC=QQ5^4bO#;pUP$yJM}EwdF*kRu15U)5^_)F_-yfMbJlYg&7>ilb0O zZYZZ^8&w`-9Wi{v>EdsMfup}rc``esH&Ur&I) zNcGNf=*vjR=1gBs!g5{0Qtmz9+sRWRW83X>sj@5H8z?BqZ^DG`QQ0!exV+sb6qc>t zSCF?RnnDe1`ze7?9MwpRPLu>mb<^CW!=sA{)|D(i#GQ z%s~>V+F(x)1NjF9@AmkF&i_gY{8nn^jt}oELI>mxR1g~!$Usj#q}^-B`Nr~xALPi! z-E$1xd9`>)7zWusa1ma>COzPN2x;t({fS{y)0C;D@MZ*W+YJia&~+RcBjq{wdXjh= zwvA`1w&0hz6(yCX8m zTN<&DL_T1veO-oSl*BYd9HNbM^gbkmg)yN<17{n4=7xxpRN-8*4Ee=?p>S-byxU2q zC{k}QdrlEph++7-V^|`!P>zvhkfKXQ3&^Q&oYGxqFVZBQ(v^V#j*ZHGpy2{B-s zu9inTzVxh2ky5cEd3r}p)%4q|g8#i`(82X`Kt8B7-ncW=%sabiv8QjUp6kq@Jv?uNBY4RNX<9VUhnc}90vcZpc6HD!vN-D=HKR}`+W^iM(G>MTXTVcSVSbZf?3)d21Bu?Mp0y~0ZFa|(_B;-_1$YARFU!Uf? z2#6_%mty;LKU?pssg>g#|HTu;g}1je2^r0?bA}TKgPmB@33>xV^#loPq~Sve>xEZE zDlhg>Nun;OoK4`Z`F3JsZB~rM^8_sSmti1|3H?6@ z#`*JvxVus=KwwIs0jgf+9A70NJdt6~C|dmP^bHCGN{rX>)|J9W2*XdX^?`5sKasez z!gB51m(lCC@i)hU(_^T?{I!nE%K_P|ge=F0q7vFoHca|bKonw1mlg3IY7}W7_$*xPQ&qQ!0g!W> z`WS+L)7^vjJ~6(jmH!NPYC-&1tOrs09>D%dQy;v7e5g6QFkMz+oIa|_u;j1i>ebyh zX-}P8JJNHBiC+{vG6E$qBzT%u;0?ND&ha~cK?w{CAjd>B?x)xJK+ zT$$`*M+*BPZitWO%OUz0_VIXDRwP_17>60V zCg?Pd#yoD-vpC^n9=D@jtsh1-wFzM=1Cl8aCN&i3tlu5O$?KO1dKBs(R;Mo^MnB z^!MM|f289;dhFpG;QL@_qBR3?;MZvOPK;MDKg>~cJu~;zYB9&3TOjpE>m5~S zr12w(+oOa`KCf%sl4jtV=cp|j-YClunnPAm)YgTFoSqd@Z@!!bQ?FVv*(Es=vVo;W zf#pFZ9a1*aV~@Cpg$IoGvhg33N5jfGt42-Bxea_mP2*tJZj z;;#?MUUL%*feY=)ivBI-0`?I3^LVNHW42G^3~=DzSPmLmy*yOP|Dt1Uqz>KsJDnH)m{0l zwcTE%t5tVUHyi(@li{@3#Z-4cn@Fu)r_H?Q$bOSdMmUQPgUmy@Y%0H^)4^BBOLD*r z(RniIt4SUviv4zUKr;Uh-}HCLn>Lu3`05rIA4~cM>>n|rU}~Br(E4fXHP|EHnI=wM zRE!t`bO}QS8TuwNQadZHtNRSCA*|8x(R#{09+aC`i0^iPfvq@~rz{pW6nN;I`lkD= zQBk9%jYa5?cQNZFDrGzv#QNYDo82HB7#UZ}JvGQqf8o_&RUE0ylij?lfNf+zfnm4r ztPJtTV$|jFD$=DtP?OGWd(+38-Qqp0ia|GRGtTlm8ce5d*s#@^n>OtUOEJ*SQ`fiI z-WJ~h0ex7eI{d^Gv1EHTrjhIKCO&W26?E=UcYj2Q5xf!%(R)29TK!yHgpp*5;^b?I zo2Y#xyL48N@R`X&*l}*n9$hecq{tNd$;H^lrJc8id8@apt@_m2jHQBdRxh^lg(B_r zy2O&;?5nRWsF|Kpa2`iJH zoZO5o(90?U1_Gn(vO78&L?Mbmf<$mmD_*aJj|eMBsk8axLnuo_8^=+UFyY*tNHLHS zq!Z#yYhfb$vRuCxW&po&62B>ChH`q%Is z2u$IY(H4LvI?FLYC5?Cg?&4upAguEGx4nBu~A|RFhm`tj1=+H)pxR0xy zaZWjjGk3Bo=j@5`?fFY9RVtEP>G;_D;`;*Z+J@&c>y9YCW|}JS2n9zLG7V-uz66uB}TAuCW8?op%LS0cp_)`u8j zNb@Dt2V`@%me2>DBbDnnus6d{=UZ2ep!Ydv@~)DDf!1<)SxZUF(->AUE1XdGHq%_# zsvSi3?3~W>q6T86+egrJOatW-yozcb`uXbpk$nSrQ39dCHfdHTgdbKBF^;#gJ{7Fq z#yjIPifBD&?L=hZP=|WCk}t9hPmv0~Jm8X(pZOk2p_8kj0-AZD)^xS0#B>mDRCh!) zPgvORhcs1sa{)SHx>Sl!BSm>?oC!MV)HFjiGE#Qz1Xe|t8lt-%w5q^|Ax8griRyR_6|YCBpDySt+uy`m{=cc+Dd=CvqYfvDP$m8jcn4kQ%VbIO<~eG%;d2-(X@s$UwVm1O4@~Iki)yEcH*fJ6wkq~ z+#DETg}6tk9_l?nkQMRRChP8)F{%7|;(}&!@p&z%7@nwya5-HfEZMvRj*_>^ZVNNi z9i~|Q(8<<9FO$%D_+yW<`GApAffvPFV|9KV}So3y&>O9S$=4 zTx`yBAPfKcf)0Jm_TIbfp9!-q8y7F}UpDX}{+;gwxQD-by`EbQmxJb^X3Q|Pi)U~AvO!Iw>~%3v zrrQM(85{<)aB@WXaGC*LLIN@jjJxVM_C$XT3>=h3gKB`qx+$a<17pF5 z^HCnv9yEy*iMg{<(AoRN3urZ@0?v?^73`omf3{+MH$4e0N0+9iQ|*`lU=)JZhh&4WuqU%7+V`P}L< z_9NYRp)*|^VpMdzk~@vff7Y%_qlNx9>o?xJD4OHHYunA@KN*gKg)%{ovaaS&slhrL zI6Xh*C?BBm4B%*q9t{K;>ohfuL+-;usE+WV#?puy)b^_eb*VI1<`bX}iJ2ufB6{~+ z8;UZ9@^wvA-!0u%b>T?CAG_e;?UW=MW?LT<-ag6?O_Bs0#9iz}@d*PE3`1U^XgeCT z^hL?=D8Jm|%Oy8#ifz}CQ%`YPpysAnK>3LJli3gUL}DUia5M~x%d&_5BVqUq|4Ro53*y1L8o-ZWQv4C=Hx3BSZv#4z^dhwfyiMf`zLmi#f@C(J2jK&XuL+D) zqq4ZzuAL7tVShwN`Ov5NTQ)PPfol;b->6K@2qJQl`{s9)m|}hzX#| zL8DIMsMA?ybqJPRvBwD#petK1s2O$vVes++ZJ?nJRfP?IR|v!PSC1kz_>w_eRJ)Bd!9JT7*S^MDDD*UY=kGPyLknG0C&YJs)o)Y2(TW9 zVkVpD9{+1#-iWisF+gZ{)@#i>&@guqpnqQ?^g{wf>^|v< zv%WjoH}_%gdvx(p?pCxoRlz=KjvrcI$(g}a1mv#_A+>(Em}sc6aHnUC6r`QHbCd$! zLJ1*%#Iq7}kd6--{)`qt=u2vguq%Tb4!z(JYQ-kvMW{(0 zP=DAnFh;p~_2IZ1iyp)!2G6UN#Q>0DmD-JR(JjZ!>rFhzO`>~Sq<_bd&N-cfKwu%C zf+B2aB;A|l855P&{mwaFK$@v5*VnuoS8D7cp<9ONr&m^iFw*MvE4&?qYzmOKFSvI= zETlp$Goq=zNRMo%o(T64>EPZiIC6O2AmFeXT^$&R@ZF0vtH-UxJwbBcYBLDId2XH| zdHDiY1>SF~adJ3!z<&v~&TG{0OdyXd&Y+LyTF)Yym*(MwO*CBFp)OJhQrMIx%l})c zQ~7{pZS-bhV9pr9@p{p^7-D%8hB&5ZB+BG`ZDsL7RYT30y2H7?hmKQYw*c1#A!83> zJs`undC*eA(>(-INIcHG0zpK0_G*QBSYfSQ?~}owognmx3hU;WjtkxIY2&`!J9C!e zx6A4VB7ks#XCPm}h*cm#ByP$+@cP!j5Jsl^gK{2W3nQ267RX6RdgPivItQS4^a2BW zx{6cQ!cG$+b*dUtty^1q$dk-N>-M(V=C;qRNou4Zf`vO*A9bFnt3}isni$Yy>mG|{ zhw?^AL3d9EO{UrP$kBSmS7|(e0s2fkJ4dqR4c13xaxxEVO?E^BdhFG1!oCXP4}8Q@ zr!`R=0+ulEr=LjKw*yd9#?Y;C-~(~SCsHTuDlK<`qZ!iW&Fx1k0WBIqTiD)lF}8H> z9nBH@Pl4D8v8ccVtaQP9$g9RRDM&C{inOu6m4N<)a%z@88{yU8`T)~#zNSQUbvvXR zdkr#WJ!SjdqI59YlEI9Gq`NP9oVns)UuPh!2a-Ac$0sS5^ikz@RP6+3yX|eY65xenTL{s-hDhISVgVhv zCH0ShZe&T)06*ou0V(cTSSr#;+WX3im0mKu(fGQn(+uK#SOz_@7P?J|qZIYV%RLI& znjaxej-Yp$@G9%~*yDISg~b5934#P{>8d?)=KW4?LJ6}~;OqFHaa-@j;T=bM8(J}= zMZl?~>dshhR=NP>ID-e`mkEJ^L{=|BxUZ`~rAB(n2uw=!)e_atlgI<>hZeP!Z1rGO;@|R7b-{?2ERKWinmb&{SwS z5q@I;fwM?j5MEsxHJ%7|;6xH`jfR@fMZ?Em9GXE!i;8dq=76lJ9;J6= zpay5Gde=KVH=`1$c&8Larl+VMX=zO@KJw(ty6g-@R>e(9U&}Ge9f5uSjSsu7v%3IoSB~m@ir~RIWB>|v@RxvB!vNZPwo-1rV@pC|G zgil!Tm~2)kM!Lo^Y~4$c_z2~2BNA=^n5{Yjk%pTDCam{iSVZIsXh%kxq2pO2=$qgH zbtF0%j8Eqb@M9&0!(DxeNvP<^vk{7O7GE%yO9ZIc(Kl4J2qNEH;;%kP*Z`~V)8!8< zoK$$}Dwq;lEYY^Iqx@1rH#rxvWuPO}p55{N;wb^n^4Rd3#5Q+wG!wBzz@?HVDn z0rZv3>$hM^%+BSkX?oOk0h+=17YmM5=%HS#uS#=?W#6n9o{1r9Eb~6Q{vmC(i&}GI zfWX^*m}2fzgO#d-Gt;e;tpca4P#E=2Axrx+;kJgSwng72Zd3^Qh@y{&s(`wPsb2}&ff@`1kM!rLLTI5rFg6c>ULFIp7yPS*aM0&3Jg?C z2X`snCjrDU8-5JsZn|02bGi{#QXc3eqUn*=JWPiKFmEIv^~v?3GPD{#0Y8u~gy2U9 zGQT@1(Uq3=<^ySsg~*~LU||9Oz^~BZ6abzhXLC2m$QtHX(uGGZy}BYRL+G)hVdU_I z{;pM=GTqgsCMUO<9Y@2-1eknN!G(HU@@lH$m}B#ln%c?Nh`e6LuUbk>Fco5c$}3=V zJPPLLtVQ^6WBN@wgx7b!^Insi-@ovE3oKlRg%DGpp8GkD)G`HA;g9(!D?l08ltSx5 zO1?DYoAt<0P+Kk_lIEQ8scbm+d=2INRv~ldK530vV)_>Ttn1Vuku9XgF2VMJHRy`@ ziPS@ZQjf&J8Gk-XgQ!(?H=BJ_wua4?^JCv*B|Y*6b62X8HF?1GuDWKu6~BFlApb>( z{fEddL%7r@2QV%H9(4EPp#F3>NePr8Wob_y1iOD|i6$%1hB8_@2Pn!kSyAc6(ctAC z3;JI|#95D1Y;ob&_@=^WM5qYVBdPSL(#3D<%V8KeZ#7bi_GsuqO&Z9QrzP?Z+C-ND+SXZjAl zh6P2OS`t>lUQ#len$R+-G_ap-!yK~op%ylEblHE2Zsas)oyLQoKFIxkqWOJZ zq~#Z(h@KxOp)dt=cV38aOAGJqvK}wg)ue6JpOlvGTix^sWsz4>;m!(tvQITZGtCiN zR_e7LjE;rx4Pw^;`-JJXRGqb+D4p*)e)6t}SCRa5tkaH5< z_EBIB&;}sj6eLth9ldI$j;!hW7i7!01u#~wo2VPJkkKzSkR>mXceM5$#JLg5@oyH@ z6i4aE`&H7S5?)aS|IYcCpWeOXkR;mTFSg?;+o3HdNPk2(u`QvwFhH9%rMC+bOl*Y2&&kB;MCU)X3DFHgG#!x`|^PFW_HD`5n0_H zOieZuD9Bamxc0n>3o?G1U?r;_ga84q8Dq>2bvOpB17)fR`#hu z+#-&xk1s*&WjDXVZf~AQ!aAzs7Tj?29~qH(K{7+JU$$uA%#4v^%cBCejy4xVZo=bC zi%a*0$Cl>>E=zDp6IHnK1SPcm>1H^ro80O>P8G>8yFMDtgS*sBb>9>+?t5@IK2Ex4 z-8-=l_6O-l)fawN!s;$Q>Ys)C6K!ox)rp1A4cG{se;qLrM~I5cS?X!qy?H-Ap=qKc zTsBCk+F;fR^50CnBA9*8Z>ilBreN zM|w5x&}z^QPf)AG-LUB0zZd#(u|*r4i}aW88?%ype!J}Y#-MIiswmQs?2VG2JrR^| z%OB&C%*~N_dG!$a&zUksFm=eErz*Zy9sdeuGw|29QId*8MW(83tUf#VC85uZvvXea z0#-+_J8G*Yt@eFx%R)~Ov?A|sHX?So7WeqN*MQ4=#P#oiNOMs)w*XNO zmG|Ud#`3A1Ph!wspj2+V{wkubHNT#QIB%5AnQYv#nQ~BSc?OEse6tI@XpYM)-bi4i zM!c`36#2#2qFm9Jsk44Z)9Gt-CB=YsjbFxW|s%b>NZ%AmjG6;|&B z%RZXcbQH_x69u|uJy`h8&xMv0`pdXkl6lqMkM$c8u5H2!mZN~9wweG#>*Olo*>n)9Z(Bg8BfL8iFse0=;Qo94&S z6tB~$n4r2C$2F-~&FmNtu@llRs$q<}n_m~THY*>%3N%$;NE^y@5J|+Z%hV*q;JF z2=s;x5Tk27#M8Uru-Pqb5#fQB2}aTB8x=X9T5-!#(8w@Ng43XJV^+-k!q{^SH57@J z@Z5b~T=}E#AOFXnYd9|ohgga)=$7=>tD2UPt47_t8^)JYw>yb8YTci3E})S&D8YX1 z6$Bnthl^9xe8)tVV(nv;;P%{Zy8b$Lwyjk3F(_lN0ogswd7^3F=xhTh0vO^#ZF@UapFLym9qT@bBvzKX0f17XT#-rVTMlu#(55!CxF;pnr?3vYD5_{s>IE-yBjv08V_tH?N73TsChV{2&x3Zvzk^`-1S8 zmF9P0kHYWIm-S(Z(fOIw&Me%+f)kSO_YPDUwA_GTNIcN06c>L2}vBP~m@XpiVFLcu-t74Q@ z{YaPS9-+D3R}R$x-;f|{?2*LCkLia%PH*xd)Ws&eyVl{i}U z((+=@Hj4=RACuE0eF}8%M13dbxzdff&f*?3wQ}9t+;O4;%{wdU>2|48B@81KmQ+Zg zZnp*#c*{a+?5eyr*YYb(SCT2`sR5HD04UXnWzWaO;P0hUe>866a7?e9#AY1K?0UMR zlun3JpXq<(F*RxY^%Zj6uABO5|B6GeN(B{&{aP|EeY|SM{8{|25)WG-Y1s|a_Y@t3 zML!wszHmMbylXAtN)tkNLf7Sz))vbV4!>$3#Fip2uyDFR5(|t;A7+_DR)QYVt3tOB zUD<@szr+~fmB}<#a?0|kh=iJRQhTN&zU}5uA~FOS#s?od6xWXieHYX_H4d2JxELW= zmlmas_GGn*h{+|tOsAX8F>$T8S0-ZW_WkTGXC^jW$A_=x%se|@uYlt`D8?%hiyu!m z(|oT*XVeRH>0X#Eac!^-hSbgbjf*69#Jm#yYcbm;j_k15Ne35YV*#ixJf`qzhPo#7kqzF=yQdY=| z>6FKB9q_ngWs^gJJY2#bYAnTE+C=6V!TdIDF?}zKv|X4rq!VQ;Pz*P+W6>?PFj~Hm z;MZSJnl@*L!8;6ayB3FFOi!&0nI4}m#rmLwgrDQOeU_L9_Nnx+Y6Mpoty z<6b!g39$ejH9blL?lKK`o`im4X;QR=-^sQKoeJHk?Evh8tcI_y{a?R>z$*e>Aw|YBxOw^-l`pW`?W5-2jpKAGLQ7K^_ciktP8?~Dk4Z(cG zH#wVp@!sP+SnR32+J7ee$}(WHl!y{nI@ZZzTp#+}Fpdd)lw`rj4;b?X`=!q2h51=G z?L_Qs^mS@#KXZy3-Z@nY;c?Za-!!Bw`G*p3?lT64&Mc**xK!QmN>DFq+q@p<`>Vx3X-Nt)!ef;4?{sRE_H|Bw#!J}gI> zxz8{!y@>%D*FJkI1F$nKP{3E}HK)fSmy;Hl$sYtPSIS67GDkn*8`o#~AfX|j$E6y4 zFL9WS&iOusOXP3U4{5vwR)=H%RX2$18kXL)5p-RaA(G7b6CUJJ9U^i(D0BouDg#w0 z)Z8L@;y2K64I`dR7)%tVJ()ORNS$;_tf}W8AMz&8_|40MGH9`>h1QTi;TD>!kQyuv zc|~uR8x3v~gfcl&`J6%|T7msB3L?VCO8L(rngBo}so$1<;^pkg=ZqF%t3g1BQV3Uo z3x&?Lq|ATf3DM~G8W$~58SiPUnoPLxxeMafO7mqxm7!b8D5$8p`QPNYth;IVgiONW z%wtTE`{8y_DUB9^7~N%( z1eCghiVMFeMrf2LES~dEPFI;0rHBIU5Yj^3Fi1sIA&U^x3E2{vAs~`7hfG#|v?8^D zeq{Pdp6y4?{G%bvWThO5lf)_=2LQbtwFkxrI!l8HKjA@uWEsI4!`FRb+ zBpgthvh~^{B#;{vK@$p?c@UvFACQJNmk2;a)ysmQ71bONFQI(NVMpD?QxzQ2Fs!sn zOFEwh{G>p%h@UGXDn-+lqSKI(m|AH@MR;oGAp-goi-Ib=idd-ps&93-PI3!!`uvJh z%w{(Jo{q4JE+#;w<7M6f){j19O~|qVk@se2B`g_3#>{1S{>bVyrgju19GQU}s}S=_ zpr{k5;1U#B5$co=q3Ub~%8qRTH@3i`qLW&{>0qc@!{dY@6l=tOGC>DWGMSu#eU1{) zK^h~ab;tv8ay$hGt_zbC;99VkwJW>#JL9qGFWg?uzqgTXWS2X+C7Hvlnq11k-dCj) z^zH<&b@b?9x{^(i8(Inh1V7DnrjGPc;O946Q!xuU!c6*G^M z_6Hox%U4~=F58KV;&N7zD1kUgcMk9=Ur!W%p5C+N8c&;SU>TdC(GltHR`_^p7{#5f zstPw!)IlWZ22X`==;jhu1qOiM`oYcwr4z>>3B497L@3$?Nj$cYpro}U z$N!kDd^{*I_kX>_MShXb7I6E|cbpAl%*iPxyJVIC73N<%Nt7q})wr<3+ z&2!W%gl>?5UH~gW=5EYYeQhUoV=9P-s8s(kHnP&Ca>z}kU}e{D)!$=}wl1&@qdC|S z$jyWvpzP&U;(>7%k{`KPU$>7aJzLnSjb11C& zdrQ3aizl~7Z!43={yy^7@zs|?ZEJ0Z@UBFv&Iq6n+`DJ-ZoL4aRvlD3kbT5>Z6WnA z1YLG&)(Vc@KMrbOdWd^9>bVI`W3pe_&C%Z(411yi3`XA;ZTUsbw%`rLG%XV~IQGF! zL0q!_0i)v7;B}h%2kJzPcsjV83BZKsqHd&1quf$`%0cw1u{@TMR{fDBCKKDriXZnD zvcu9g>L+&H)KIfAA{%@Woc-q$wRj7S9_)-)J#iY6+B;JA<7a(T!-7>kx!uP4)Kkub zQKgj;!}cdM6M_g&8ju9$EAnnOloLl8U&=`%=fi?gH!S7PdSKX# zof1)f#wfF`5%062V#(#N&VLiH&WM7IQQ?70ni+Nv&svsMwzjye*~{~@8h<5TL?8NLc+8K+M7ARX;*62c=d zrrj=!+uj59W26)mL4_2Gy-j#pc}+g~HH8beb5^i*d4UJT3F>1FMK^+)F8=oE%7gk@ zM9HSBLVO4LlP2+(W3opn9V-6Bk&^pqWm6$B(c9R)mKcMbA@wAc;v7Nx2_+p(P#`0@ zscW;h?Rn^S`u`*1sl&C9DzTK!^q1=oY`x)Iof6O;MI@9l5?ZastR068fJuGl!6B%& zDptUS`g=0-S_}elE}qyBH3wZp$l>waydr;*;!tVvVM4BYNI##Rq~1y^?f;~y05L$$ zzt>H7O2m`$__?=9UN*)zv$zLw)IS`wXYOO!;Rl9>2kLI={ zd&l(WZz|nNqkPFw}OElX@@Ll@{s)mm(>S)dO|N1bL7S&NZno(eIBK~JlGLiO6NGwPc+ zc+5;Z!$G&yvr&=KEjgVISDn#m0QE}ig;rd?A18GqhWQh9ofW|qvcCrW(3?y#zG-!A zKl^Z2k@)qob9T{1G;^995uJ+1Wxu314C2Pt0sFbt6djt*0jsi@@-Y(VZzCBfDNS>mog`>4+Yu0tB1pl=MRe?ur{c zf+6LgcZ4=RFEbIkuf%?)@(d$kP&6+kUNV`F{|`q&n#=5bOHhonkH;z{O|zPwHSxns zy|Oxf>f<30cgGihGoH?Iz$-u&ih{lRtL4}ZKp(aGpfg>*NSGO*=~>;e;0C5ZRhHv` zD01L{v6`jRQ)$Lg5zDrL6}g`UZU8Cvxo`aQ)BCB|@C$1pxXrTsarnFYjP^U5DsQhb zJ>S*u&wSgr>U;ZuiUDKP1erWM-C5Dv3HBD#GFs z>rbuyV2)i6|v&}IJkxkXJ~LLNfzMWffN$W=lSqbC!#-s3+`fD z%=t8PmGm#QtW{|epDvXvc%fJ`?@4k_sAC5?i!Ectw`ynaVu;-x?0*r!f5v%k7NqGY zi51bE*2dPFpzTykz9UOTGfCa_D>$KK8Dd-(+snC9EEQkPtlLd#p#2%_&ZDKvmp)&b z4Uj0_F?el|I4hU%Q7M1oGhoRI@p3()kgvzoDvW+ix-+dWvQV}ue_z~I#j~=~6U@T$ zlZvu#(wU|x*}m4o1N!)D9aR|#MVnoow3V;)A%ics`Hwf zaq5*CAMAym+H-Vi;T~~ztKvwVXKOx{*OO4aLm!$*Aog|#R2GeUcFV*%n`{51_*RoZ{LCcbLb33(z=tyFe=tx5--DL7da zE7icGL|H@B-y2m?ylwgEHv;M%n9E$j;lQK|o8D$zX^>9S4G-U5+3aY*V7Zkc}Y=+t`@a=blywY4&N` zdQ&4gqRGPOtIUche$M+V7#k7x>GiEy`dE&P4RHtx9D`uk!f=C*rTB!HBcNDXU{6uF z;#RKmD=XoV>d>k*fcK8`OIH9Ch^v}s6)H`7&CDpCSOsr(rsbHU9jHrDl+(ZJ++@>47-A@M zV?yRGRjO-KJPEYS#*S}w|G*ek8i%ZJ>1rbWHuJi(%Y?Yfz@Akhoy*Mb?B&&3dJ^q- z%k1waPH-H~)En%ed>sDnqi0yU%ClLeSj`irLNpAbgU>3UCz@2JujJV!SW^zKlQ@*= z2Momj0QW zY6K5D1o5+hWWE$L-a8Sl`%A^u?pZQN(UkWm_;;{fXvwc1*fTno*;P&`mHho}ZjK-H zLVxBlS&p(HJ%lt-J_zT{-`CL@OQGZnlqDF29N}eHo*Z|vEJ?J;CQbYRZy`5Dd|BGC zi!P>FQWUU>z6)10AlqlwLCv3R**-0$32T(8&qhi-J@Lv=X6sz*;`$<`M-OD<o>__~|4;hldXM7c(-7|)3&tIE?jD3axjdGhE-=N6-y8=y28I;1Va;Upet8!}H&F#=`KT0*ovd0PUnreQ$~j4cRzBR`<_<=ri~Zr#GQI87yxj$~7W5CwK_! zxbagbLNlf>$*bzRp(%m;8z$rBk4tNOQC~R{yqMQm#>$janAvnmzY7VA`3>DzncQ!E z1!nP@&dG(*{HZnNg?snyD%=B{9i6r)9Xl}UqZWA_J-)#)Fn(|}2W2jjNtCLqZ4g_a z>j4KS4`k7s(z$c@FfR4=Jh1T6wY6Rx!%2PfAFxhU! zfcCA$hEhFjpc~(GAn(Rz|BzG*38UBJTVuQR1!F2{#i(x;PCrIW=(-g13UhqtD@#1H zrzK7)o<_j);U%saRjS#9qz97y1>fn9-|0zqjvq(i(=(x>TVrSM&Md6|M!c`HGLw&l zH#)G?Yc6q)t6~Q@r`BoScF9+JEXxI-&E#H)auNIOI_0$;`rVA4vr1-hj%c6U;g=yLurI9wk!KG964lx691aIWa z3&MOjjfCKl7+76p{w<7Hc1cAv9`95K%)`T9{&$uzhMi-u^Q|`_)QWqslyUE_a}Mpl^BoPIb)5k+M?+kf5%f zC{Rb_U5@{j~{AK?5csFvV1Gb)o<17*4to%b)s1g z8i?2I;{~EICua36$g;D>fkY8pBv z^Hs_ekV{qrR%~UPWa-lNal$m0owi(ljh*ADOEm$UHz(`XD49lt?CZ9?LFz9+<;ePp zz#_JMonF|i`d6o&tNSZy%S!x9UapNFuxHK@X5Qk7Keg;yT%Qg+qdc2+;#>nH*5c1X zDD-3;2km>)l~^(9%FnDIO;>aoR~5lp@KT?E-YVyl8@!lukwc7<7J5S$QvyHu;=4rm zq`qYGOUiZausr~Eo>vl)3rf@%<4d7uxEJ>&cYT+T_e0Y`+9CW=d>ZsLEjx8RvJah} zb0{bM&V(RUk~@N`Pu+{YM9kQd5JvJXN_&(=?$KatZkF2LEIfwm`Ob5<0BwK!nzm}r z?esOYK13MrQSxKZeN~S8iN0CN-+!!6@57$E4A_`kT3a3upP9AgH*BpZ8!)u2(8s)a z()y)Ow*vFuM;&jDgaVDzxyA@TMMJY=d6+Gid}WP8l*9-hPhw|#^lMVdQ@sbJM;~}N z1ScVWK*Hg;Qn^!t;SfsLO9l4`<}Lv@wF!tM_It(?UCESYkAc#f?obH5r=93dp|*PU z)aDGE@#&sp?M|OhR-n{4_6uZLl<%ILYI^?Iju7~2F{L4H|oHLT97#ONzu}e~h_fEn2HQjHRZ!TkZt27-AQX;i4DYMC`IiT?(GAn%^X1n9;Rg z`v84}G2ylcSeVk|P&4)Fyh};)Wc&bY<Jd@*7%Rqzl~4iNnCuoJ14@Vzq>F*Zr?KCa=))SQS^UV zb-tlu=mmR9+`UN@tXs8m{o)2%co9z@O{j=rq4J&DC|(?v$^MUrKjs1T$0+ht`_YI%=##}CL0?ZaWyj_B}@kC2Y#5I7j7DaXQ zC(OiT*1wG7IHH3R#ifqd9?n?RxI0O%@gWdQXaCjkKTwW5{Lmk&sw;s5!$kDFg7U)h z^qflq(Xo^It(==&9P;J({?r;~52$Jz@Ga$Qqp`&{nW!X2Q-T(m8L2KBTVj`DOJX%8 zDB%i?!s*eI6&i+7Ua=CC*~(4=Vk`Pks5)G7$wQiqFLv=6ZhFZLH9v2bz@JDPA3bGGj3A)HL|G9GHJzZ)5LM}F#C1ic}5$_}3VctX2j_g~s4?PF8bxb+U>^_pJ2XRk?fi!&E9y;pq(q09Ln zrjDLJ)#3iCh&BQQt*ZXlgp}c~&5p71hCos3T))PKpLosSoXm}a`Z#XM2GFVv-+;tp zLrTY{a-Fua8%uYV;e2tr>x}s_#~FLfWz*yoz(5p;UO4ybj$RUM$NRU?8&g*RT-aWG z&D-xv>m;L+{Fk~TUkI^wf7q&q@*wC`n1_72J~ibC4_FI@4AXy zsUCj<3Y6+t{xo~UF4XR7U&Rh>%nlc-Jd`~7mi+-p#coI-BjT;7iTbKq)e(2}5mjYv z%Zo`M?H2n9_Nn#pE>u?lr%qLcLJfC$nwD)u0l&vp_&IpULoYhW&|WHGdo4cD)Rx3d zku3^m<``t&d@}!5-ZLlzDqZRW#&{t~{AYQ$Kwx$q5#pVbvRF&a(QD%I44s$tj*3Ql z7daQbR6`r~00=iUj&;Tc2v9|*bi;TE{rh8bQm`X{D*P0K0%tmy`j4)F21?d{MWqv5 z$>;NENzNrSx}PqI2D0np=(GTr9pKmvbHCtTM-kKQ-fk}tL1tu(C20~MWu~LdZO1Vp z5$5kV+1gHjrO1$q~iEVf!?<|}q(NxG&31;AhmB`@wYok3Fg z7!UbzN;2Q`M+luPPom%Ed8UzskL2R_Lg`zv`~hI8>tvkhRy_?bji>c-qGbe*v(-c; zNIcX_WoJDe`@3BHPDF>V@|5Z!J%OI=y{@>$^O{8u0sP{=xeNK9C99f&7sCm|3zB81#Tt_*x)-C6xA)dUU^QL~VNgk3T?ziKS)b z_vj%$d|&$K7ytiNxf}Ms9zN{;$877H=J&rp&-#NKEgygFJHM6PhIdY7h|0M&4__<5 zJ#j*HfByk$lWKdvS=rqUxZ(52%I+LP1bZ|KX($_IBMfu4RD%=d(~&j!OxFWOm!f!0 zLT0rYU$ScN#0u_bH@)aBt{D&=AC{olbSuEhZ@HDM-v^wWt8J?~ao?K{gwrsnh;oA& z^WI${!9&|&m?6z-c76upufjs$&=Z<~Gwgt^68%f#^|9=kF2K_^mtnNAP4R}3_h6X_ zcBYH8U5W0Zeu@C_*eyIDKEQQcaDuM;vL3TQh5>+_8!Kl&8U&pDRS)*^vCkCGPq%3~ z>)!;csOmi2$5Hb8awugNVWVN=5-}EX$#CrN8#UKRP^tbcU@?S6E!yTzXyNbRa{1d6 zWE+E`7X1xlr~4#3FRLnfFQ%ryiMux(`^BraQH9ckYdzbZvO70NA|n?mJZ5)qqh2dfI4FB8oC-58 zr*r#U`Egmutb(|59mAhr9zJFMSOyA9*D8J<)JgoYPN%6>wWs;}m}7!8&EEE;c{bNi zV@{QNs!qV%&n;^YQ>~(<6aF(Bd*%?c;*aYLH)JHt363PRR)0FSPfoOG6F5gtrhJ-{ z5IiQ>y&;nW`y*PB3eXSSy*Domn}wzMuqqdBB$}PyAvBl~B%%=}P-APCn|Ba}Ddx5v zD05BvtBC*W+hi`BHzpkN~cS1uwCux)nFaFvara-He#vntnt`yL4}5wN6tJ*%&OTY z5ydEd*u>ZiMP{nBYPCL$X;pfqJ7u~1w33|>!I5XcB3{zUUkHfvPG$B^oWiglVm3pHeEm8Ejt>v#U!`gOn`mi(?f>@JU@~BH71z z>)mI<1R8n|gBrD#e3~k?WBaN*%6N>G7!&zhIjbE^MPo z0rS%q4L!Io#g_3cKQV6ub!>$vx=<9->Huh#gyy93-$$3py%Xw`{kMel= z;NGVbhTVEMwhU%r@JV66Y8)f@+&$xpLyM53fYZ~{5*-jj$CAm;&G;;fs>$dKx0n$9 zTfJ3bd{$|>X)8Id^`Ls3%YRsiNnz{snQWh5&f=CS3-|5Xl_pe6;DgU`1d_-EF50dS z^RJIiX_r@zER&`Ay}lA>y}T1M5abPUycwlulA1hX6Ld}Ag#6a6sd<0? zb(5PJ)WP70Lh>3`s_u>Q(fy=^vRG&8Yh zISNke{q_55Z6J?)(c|woovXP{fTd|kk?0IIGr|#z!W>1TB9Jcv`=K)Np}>?NQy>g6 zl{NNR(Iy#ejr2&U@?x;o*|}io;E^MIY15@})r$n^xmkkN(BY#zfbg9q4k_oBTr}r# z6&fT-^xe>zB36W8&C7uvMr-$-Iaf8Ue7iWlk-0}a&ECk+6~XNcBhv?#E6_Fe<1K=L zLf;aBb`X1W8PZ~E!PYPTIonH;{ zd7e7At=@yM4m?|N{o;Wvb}_gwN~0})>IXG`?nv{V`wuZ}j7U@+Va;01sxhOda{*(e zENjtzTg{Llj8KYDPNu8RmREAUN1qGXXF#S0-0zsIm_A2yD8(|2mF_;5;l%aMaz!{ z61_#+W)?Do9=j~hhH{No@)hekV~#SC-jEdZ-T>E($wH8Kn8C#I{%~&WI*5~w!;>(* z(vi)lAQjrQ*L-2*qKxj@O2eU|eMjsR3*pW133;}8$zhlr`l4%|Tx$hUlTjaPRQ743 z_zKFb;k$szrFi7kJXBT|P^^E4ejSc=Rtrl5{+SVlVyYAA>cGtR!y;ql&l3E1=jNQm zWEP*mS5{L`7O00=$9S7265qeXEkS$xCib9zm*wvocZ0++IaExt{*i3uas3tSohN4F z(sa$GirOP&Y2%Cds!HNQZh`G)SM?oy9Wcb}ez7F<5v;H%0+;GC47f%>XG5IpiXn)e z#3;=sUpqClhOTYRjd9izez;kjh-iou$xanl9j58cIos^8Icf!m%A+hQ8B-jOe47MV zi!}x?PeXTLWr@;YnQd#x&6?U7G{1C*dr}Fnh5HT0(ZIogfC$dBv1TGLPJC0c%N8L@ zh!Ht57o59PfTqFzak+!X_meEMqcK~ z{1&_b*3vyf{T2)!jwq#cO(3GohNz}f$6KeZsj`Vau-wy3xQ^=7souo1WEinzlPN5QEd!1`kfPJN$XQp;>Nj?8; zbxSvcFW~1=NPC&0W4QyOa=rMQ8HqDqXX{Hei@h>WLheNbUuiLCVp1W6f<$DsCshSD zvhFeqP7w(|um6Jh6sexrY;A-Cds30riQb4pOe&f=b3B;%oeJP|Z|9|MG08ujZfL{R zOL%GEOvtzy9oXB+Iy$9mFdbdp2d%rX?47RRCBB4or}9#81MH?Hk^KX+FN*qs$xGo7$6VR%Ig1?& z?igkcW!_9tU$pE+*D9FC0K0rb8Fd!dwqi_NdJ2CR_BaP3`}(Jt8BAyIgL$!}P_6vL zo2#LAwOU?0JDEWx$N$r=WcQiz*H{S`9e?sS2o(i`(8`63m>4*h=5tCW&Tfuy?e zfAP5j3zSlBEan&D<=Favnzn>iWr5&8kOc&;#g>~)w3m9o>CO{ zk6-e(ySf@lsPK>UB5+|(HMGUwLxAOYMJ#Q7avt*R%&m|yBNrW)`z5t~yZpUFApp{_ z%e1H@GO~nGO{35lDOOp^qQ41J9C=enucpvEvdGvTA$5`3(L%NSBi>Mdpl&GzOREY+nyWGqR202%w ztiT&~+f@{{4t$$-M5#xgTp=8iuBoksd8H1z+zS~H4ugrt?y|_Ab`){4+}tEZ~>_HH`T*ZpY5e$%hx?REO8Zs2v>KkkWHN zPMTR=+4uwo6D0s-@f`dJ8n`GtPv*tqS|r1c)m&TP}B6PBX8g5x{cz<6CWE*l0_;qm234b?BFC*JT{ z`+ueGJ1cl3Y20^8t@gLPiP}4s^jx(*FhP!8fC+3l^?5mxP}=@qERqbDw}h}3=w4`- z+5c(Z>>Qex<9_-Gf;f7HOlyv!WvY;7TXotQ|6%|LZEV78!TmOCNxH?7ixJn0Z`s{i zTLz@}^^Ks5wB1{(_52F@ko2_bBGV$Znt3|7hhI;z(jXkZFzvd$mw4tRU7I*NaRKC3 zmKF`~=+7T6E*|LZ9WLChQc2>)Rhsv_KdX>uwG+^ON@A{`WKVGBfbXI7EZxP*@}ohS zbuR|j43g!JuJnRbT)6dgyK*v3r6l}&889}uve9S*D&3?ZB^a#5!iYUoZy!c}qFM$@ z6EZ{84Y63?jR@qBz%id$iq0>H)Cig))3s+Riw|QnTh9jP_ey3G`}>xf{AQ^xUKn@? z+rvQ^Gz{Ca@9s3MFah)$8rP@*KTJiZJ0I3M1R3HVoXbM#{0e>Iuz8@U(JWF<dW}gM6L5E;kQ!oImys`^oA$pmjO1?Uzz1;~M=X z7Y*9y9AcrCzhoQ-+sXlHKdwSDR zpO08u{bu^uXpK^#2V_w6>oM2aU^rPnkPV2&(-*kLg?2QmwClmz$h^(>$JL zg8kJ9maJ?on8fEsHjrXXtRfC1sp|d1R95NgfKk=dU|Wx;kxG(d!a`ZE#`hShvt39A zpZR_36i6jS>bmA#%`s(49@8)PvGticc1mj3LlA{qym;tZ9gR@jn9AT;wIxb-XU*1k z&NI5gM%W^Y=s@LOyY=C11|avH+DZTN*y-2J(`i)bU)$f0)?kEFa8pUJHs zU|3UN00Rm71v}=XuDasPj7Vb{EN*`4Rv#mI`p3ph%4HLcl~)&lW#D93NPz;JKJv}( zoY}#f$@7_!9$ceT$80ZhPgA3gPu~ZH!2ZR5<9%O~Wu9?lyq}gw^V3PO6+XV`Q~xXa zX235czYP>8PwHd;d9#fTng>YJD{6UR&S(+c=eJe?BRFXrnmK`N`?B+9vp16x7}+Pt zB3~~A>}p6&ZLKt8cob3t=2=Ut%2Lxu`f5oO59!A^z;lG$+E~OD0|}O#YJ3)#a{g@~ zPYbeVm_H(!Aok$q{D!z1r1kpSn(}#{Q7YxG8W4+LGTD$Fo=J;>6a%dP56*5G+Sk`N zw14p3AqF&RZ6185+04jn?nZ__F3GR5aoHW(oDurb=4|U_a4*ptml>XtLLfc;SWA}m z5}>(nd;#JZ=U+0;kxw&saeDScAcaTZ7R!S-!e zNBkZb+PP?=y!CjlzLKoH{i2ywvGMaAX?umSb*J?uBWfuzmZeBAseD14+ho|cGVbC& z8SC5KV6B?nu*1FTPgHH#YKy%o_jGx3h;bV zRbjy#BN@o{;a$+^>++>jZ=Y7N@0+h?oN|wRnWXTj4^#K+EF_RXWem9%LOgfOnOOJS zdt^i{a*pMQA9$laS0l?J-w|BANnrNCdCkv5KUH332`J;231IIWQE1n%*LNX1 zT)Z}@!9a(LM|Lp%F}2$rzo`buuK&m{h-_FtEGP?YP~d`@Ty7w9cP$Q`<;vlJ zHBm(DLj*H>QVi3?2me(Ik`!Ww9x@npHB&aGgSzlLfFDkop()&R38Tnuvh_1i7ZLNI+HH{$Xfqn+Sy3!%l*r`!t3o z9pS7_hMcrK3H+)qC)#32KL|u8SdhpN5Hz&;+GfzS*LvC-)Hj7KgKa1>z#eEHfDVA! z46bTNwrmHM>)(kjchwGVglc9R~n3s2L4(wK5DWdjaYsHoHE{^0tpH@j5)ye5uQDZZxHToy zSdWRjB^JRC&Gy-&-d=U=mdGH9WU4M@2$7oTlSc6a{`4Mwdt-6jj$vLRMy>z6|D??! z**rAJcJ$Vk{#$2* z0NQEk_9#awsZQ!^YFp@|rxWvD&I1n-s5W+oruC4mNtXF=t$ zpjwbwxq2H2sJZ#2d*S_LFgSicT2?FDz>Jh_lqK!=iEjWL)(2;GR$Gsk7^0UJR(^V* zB;%RhLgTLi@M5~BU$FcYs%4?cTSq0Zqd_b<8H5Vq2e^|_ly+Z%zqMKMYWyb;6u7&N z?n3A%dzi6hA{N|5BO1~QAB?VG+yEb&*CS$!_AuYmK;k>wi$>j2l$^p78ier zBrVy6&*&15izMoU1^EkDVckwrgv{%)rf95e{OsZzg+c2OadK6DoCxnkxj4P=HS>OW z%hUCkV7R(^NO06uQhM2SSWsOp7U<*?w`&`YjEKaD%&dbCHmK!5G z?Y9UPTbo+yT5ar-ZHZQPMs9_9F1P;K*lJ%Xt^BjBr43jkqFY2|?p>}PA|XdBYZneS zZh>LjB1og5hHmhqRdz;}WF1i%(gfYXF#DjVo3jfC9k;;oP2qvXHmIwY7^ULMU_@@T zR~9a{%VqdBu@X<&u49@0;Zn?h>7lMbfxm5umQ@%G^stC}3PuIkg<3VcAQ zf~f>P2QgwSNrJ)vwo`Ci`g&() zPYm4Mm7mwu-IZUkXI(5poG(BX8 zMs#;=!%C>KDg#q6s2@mxB##YY#+5Owl)^C?6>gY>xZFeEd~(|A5S-cMnqHvp3Wvl) zIfX}QY0H#z1M&38)LV6GR|UZuWBm(qS}^4I5UV`Y0$!`$E!C?Wkx+!KSs4e3DNDCR zk=ziG$%_fdFOpyP8o=Sfc5xYqFMy9X zF11ejf$uq7V8c{9*avdtrSg*mA_ z?dj1>-Gx4d`)_)zHZ6em7opQC32~cCV-DHn_gUcZmblCSBdW)-Cto9pA%0C`tM2*l z?@yC0_;@Q^rT|GTOKUWr0WT(K)dvWqbpZLE~j`QuJo32?tqaa{k_1i7GP=y7H|c@Uj+sgc!BUDjG^$FNG89c3S-7u(#a} z;;Tv)JWvO)W@RUE`iJzl_CYR@7_^nA{eruS&x_Hk+n34d7~;(Qo1n2&D|bvRnHF$7GXilbcZ^Qwj*G>zvAxr{;7M9}tT7xe zZ7eM-^+>k?dbf-A2sRjwcseL=qwMqAe|Rfu)Xe1dt`qVVXE_Dq`+MGGzuj*08T6#Q z5PsTJ`!B7S8R4hrX|(iwBW0&qdRX{L`5Fy9FS0@5$n*%1P32#8*1Gy&giX@&)GhX@ zcbd#qWN_*&a#yCtzmb(VFQ+Rezmh*KQjMFX=D)I4Xh)s3Ze!_q(nXlIZ5A1(jaQ>{ zspiXRz5&3q>`@bbyJOoqdV2j!^!9CGw`*#{R;$ceT6+DC^B77RJ&z<-vhl=zv^(#a8s{s;1gWwys&v)`1N8{ME02x1_1^ z{`)!5l>=XvS~!`lVvn9|h}$j@dS_VT5Vw!!kE&2a0-nlcZ$wokVu9E?Jj6X&AGb{) z3~gY?2f5w)s><0)iw<VKuec%f^3f-yJvK^wtD$aU#lK$90(X1+2+K^jJbn;;8XwF-M+%&pM62{52@DfpV ze`_wKFzvrKtCZ>8`IcX5`apiMPZUn7K?K=?{D4gAgLCn_g-ns}q4D4mi8_E;bnbZM zlp`XYXlcgv1f#h71X)Ntn8aTb(!fbDcuOYY85)EOqP zl!lEj}t+ zSIAYq(2;XU6<59>&1#bD5(Z?o5bI@iquEtHE7F@FVgG~U&anB}WzLv}w>YcM@?lpN z_}airFOl8j^qduF|Np)hE?2V}nrU)*6V1~hyb{QPn?Tu2^V)$(x#{3GhV_jGS>XN6 z|3oE2uMpVtr9drwaNH6$J$sss<2tA7ES;^9u3h*fWW34gKFiSlPuT8id_ysf!!Dv3 zJ4ja~`QjRiXlza~&D23gAKGUw9!4EDBQsEM^$VJR)skhdywH02J+SP1Z23me@i3I4 ziJdzi$BOZbp{0Bl#1b>*(MX1z?FDCdzKw|bV5(*5+tf56F35Mu}*I9t17tn_X;sAFgD7Z?bjYNcw($Y|SouPGP|mB&wRU zi=>{MMo^xyp?J~|P9lfe@T^RyTG(%tdcqId3^hEEl~&qN5h3Ywj+Eguf)o<)3hJ&i z*mgYGJ(ICrw=!lmrZ_jO$?YOMn7>sG>S8Q3p*g*{E85LzmS`&dF`P%iZ&I6NOpDo6OW&;3_dSUGToafX>z zuG(52qdnMHGOJImJE1P@RvfRuX0_pKg=@zd{-=Ot6CZ)9j6%{BC8~@p5|xsTLBdo_ z3}KqgD+0A?FnCNsNp$B&+X22w8=<)FS~=eB<%PhVnp@=t2eV zhk;}G=G4LvkoOt>mXZMBr@r*-0;P{W0b~bOBN6p?Z(+<@7#(Y{57Tl(c|3t1@hyu+ z!RIKad{;|a&vSGDopQU-1hYykviDH+l5YB9pkD8Qu7&tD!a)usJz2D?W6)S< zZve!Y`1a&SfYEVX(gj}lMI?hJ!WS8}6jr_-r9pt1_E zY^aZ9@~LqcIEqLw+PPxs^bR`3Z<*5Z$2WX4L+Z0nnTHD4n2<(Oj2FvFuxc%;P$

    <&@$xJ=1*qibF8}O9UNvYAY5E=Ynx4^B-^`#_rU< zE((dyI8^kHU_k5bEB5FeznIW*U~9IzLEAN-1LCLJIIb;1$&@E|&+0RmxC;JO4pPan z&4DfM&B|K9CQdv|4(}M`+v7Xxwoy)5<{X2i+&=9C8K`tR5jj#(Jsf??CFQhA-mc40 zTQ+8=0d4Ca*F<}Gnsh=lHHsbLNh@RxLU(xg?IiVjRLB!UV|4z66E*L$+JGJ&E{NIW z5vFNihjfq@LD%ZlHNl}ShDJhyIQ&fNOiD*t(l*~vWeEvmh9`(bkz>CY$jDpk#mI;libY%(`y#hRd?P1bjVE=iEEQ2dc>ZA3QaOniKAzNZc@BySxyEN_X_BcN}O|3 zT=cMg$gR>?MIw0$9lH!9;C35J4lTcVmS>*Kp+~{Qf*9v6nrXBr;pXd_UgvMvC9?(%Yrwk~;Crb}9S zZT7;rw?1>M#~_qHzgurnwg-^A3qe5=k>K*ob;y=(e3BQ+m$!rxr?1tJ+LSQCnF+5i zPbF3LgtLJ0pej$W%RSeTvvmEFe5QPPYX}LabqglwYxOm#jF=6i#;>x&=D4!EH$F~E zDxgDKVjCYe54e4RIzx+ z&w-38H=hE)zHMY}DTlRG@RArVE*|}Tb`;o}knTZ{yp^T;g6W2QkQ+D?7T%dxHQ*Cs9RbEEmdD3D3afGnrL&NLWmwWT^5Tuf)a%&q*YP4K_A3upnIz80%0VnUi@ zJ3e`Y3uRAXhXF9V^*?VuSVhGbnMH0v7LIm!>n3*>ZSA8*nyWKBl#~||08H}F`U(MqJ;9Ac+gO!v&CYp*A8N`&=UOziAwe?V7UDx-uB9h{wVpQ{l zy#BurT}RH;)sm>X36u?z5Zxjw_WW`HD4cUt`G#SI&c7L72n0zkQ4n&Ci;I2-K9uSs zkACO(aD=NRE=~KQ&^6f7^rs-3?WzNP#Zb-hWGktBOep5U`rTbTFd>ef z@W#Vx{kEJN&;zcbAuEO+5i8i?8z~kR`Rm_zhqrO8O+RSG@$5CJW&XFlK{OX-3~xv{^9XVyNFv=`V9;YS#&&uLZVMA_(a+M67#1Z1T84BBvT8EITjvp3 z_!nh972r=Z-6T*lgOgx~ex8MpP+*vaBvqL6m#xsw$G@lqzR!+X=f}cnT<1c(WPn1w zsd8q$^|{ozuDQtz=)3e77aI=O4zf>0s48>axP=t~+SuC{q}6m9d7tF_v{+mP_cctG zc?uQsR5v#7T74&!?*fjiq!*S1%1~ODzYp=aVpu`I2uaWI)o=>4A})HnXFNdaYt^H- z)YTEJwFGQ?3G%WffhUKbt55!3aE=2{p|5=x*-w9dP zwVT0!)YYBS9pr)dESIO>J!0ug!{ix<8UhutR?C+dGu>D81Y0lO%#E?~$Q&HnJCNBL zPbibVA}#(=RF!lYj2^~`q=Y$^*f)b0ukn~m%a$zGHV#w8?pF4nwcVn(mrg$bV=x)v zuXJ>r56@^IS)}}B;C%N2gP6HqUmFvr9>xft7pm3FysFT~3R1N(IetV52sjg;f*b`$ z(UEe$atG$KppbrgY$ps6m}85BcSAw5)@u7itnUs_s7s1D)lIfT)2p@jsp-LhL^qwl zq&%bJ@Vas^jguBxKdgfI?>;s_&42N)KckYAlwB5LXT>>7B0h5kn$4A=biwT9#exDOimvi_x z93_R)svfB*^LUV`Nmxc>QCW~i)w3L`|EX~i;QA%gF-052`-P3pcfLuHYIV~9llXM_ zW9LVmc4cMzq3+I}_m>6YkkOLV`5mPC(2iJN4a#2v-akw0~S3cT&GR%q487j05T(I=6i zsWUH&A4-mCDn`zD>y@dmzcr>m`-Bf@36rp6Fy*CDy>nv)S10VVTOkwGi>a@4#(_w~ zRjr{Je~;1`Ku)S{#J}y;X$yps2hPl&0l1{_nd37cH2m6RbZl&*&KTELE&e1%(0)4y znLPaXuK4y(*>HQUpBn++TehXm_qw%gxTfRP*E2G{9&>9|@G_?j?{+!c;xdj9wX%^2 zGf6Q7Au7cnknXZ#fct0BGC~Fvnri^$`O+gdDChtc&nQlZXyfpYAX;RQwQ?k{;Ii`s+oPb1X z8u@~0_AA@_u>IIRFinEnHoY?4hXZ2wwiE8y9iKs0Y`=W}X7?F)Fzxb?iwA>crb&kS zX8JZBbR0uq-o?*ox9HV6Byln1%XP&h90s4dszp;}q>&998NWbVbxdX)!Pv*N855mW z=ymu;s@8F~4$kQR;Wf;0#UzXl#%D?{fNcl^SN{ydSqWpIVOwKZlaXVdMgF>AtTm@~ z9B~f3cEG$4p>BPyts@n>cQ3;^+7feFkWfBs28N;T3veCi>kgPKA`!OdNXEZ%+HnlY&$=H!l&(2m90=nbY4pUoWpU}3}4S>t^0<`=^1wlGq z#)t#~bEmC$+D+|@L7Ru^tQCNg-8M7nu&58O9Xd1p!Y6KKDf?{*n-c{%+XZQBf=h$& zmu330XNF9akh)udiOXNQ)^ICbhixenDGohW`r{ZgCNjXXj>bccDZO@OgNU}WPCLLy z$A0-ZCfv}xwcMcr#`HXQ4iwEd4q>_&Gh{q;$h`>p$I0op3E;FY!$X{G1Y8?;=mOLc zA>6_puoX z>$^~7k3PkRGR|22EJOVA#F^_K=18){+pEF#wA@OTvY=T;rJ9wv>X@{UBUNgwg8XMA5M&$rPawj5@_$DzL84q&7enL)Ye}Y$EMmd~P27VC zh}pKH;{i}`(MBIfW<%yg@Oi%+ap!Q2IUKnSnTsgIC$&5 zBIJ*`g$I68iVn@uc8I9URgB|wd=erFG_(z7o>zhKnwAnYGN)OpcF1zJD!w7*u5;CF zx`8ZDV&CQEMlzY%W<@qy7?B}B0*9d4?|x5AuWtY^<_jn zaSm$)mBsYjIeip7;_uXDpRnyWexNMub6Oq}mJ~8hn-M%1%7E{uFTXd8l%fL^^{J<# zh?p3URq>4(jD@nrqrp{KAp5kY5l!!-n5c`0pp9_Av$vkR+Z6+>6*E%C**_gZa;=KN zS|ct{Cn156U$`LEmXk1!F9;J?d8NsnE5GBOEJXj8oiyy6$IM-j-L>dn03_BoHO)*F zH7zTq+e%SjntxjI(pot^jz$-hr7V(NYL@|D5wv@)emnJVNIZA6^oLTF2?kx&u2KeXF)MViNOyGlo+h{~Z(=m*Um3`a9dTacf z3G=yBU)5Cpm!v>GUJ2A(_MYgiS$f5<_pkpw3UmItC;Su1y7t@sd~@K}e-;1#bL5Ua zY2W<^LznUIwNp69wm@Kr6~^;}{xvEw0J&#k4MWo$U|6=LUn6y_ z37iOv)klYm&k|b68P7KOH=SKK_$aZGA-3j*$yBgkrYR*F^Ado5TZn&&kqCcaUX|Ua zI^LNly(}$1*)jGZoPvlhXTk4=CbCUKqt(vJ&wyU6Xas=XLEB}99fr_qelUN~>Q9ex z9cH74eCly5UL_0#N_|}ueK57pj7NYcE9#!;WaX9CvKIy!H}NDf(^I{uY4`kwl-;*t zY*4`F^2W;SQ6T#;@`MtD#2pd-%N5aBMw-4Jmpmewl52h2h*I#*WoW9ds<+3i-qKq#P%^F$+Dws(Rh zE|N|thuhZI_~NE~-RvFO)J=RpKXw8BCN`H;Mz{^Hf+ z-!fZp5xNeC$b2#dbc_$(vAy0&cDFV?e1X%R%H3D%i>gxi!rFrdj+Jf9b`s6HsfnZu z=vHfWmXr_`4*J9=N|G{3=KKb*QxS&Tqz9rylZBN}P6m-{uxbh1ie+Lw7FiS8tcvES zQ7fri5>r&;Rw-I@4}KjdaYVq!-uC|NFscib_fk$h5#^8-h>LN!wD`(DT`C1HQr|3^ zb_5?69EM*B`pbiUNUUfT44L(4M!XQ8a(uCdn(1n{MWrMr5F*Tltt56nu;Gl8B7M!+WnTri&70* z0^%xYlMW*rJ^z0?I6}{5!=Or>?|{%0LiV93PEZ)*H{&(ueyilkQ z#M$2;;?XsFnog}=uqS&4*%2k=nFtVW{rMYRdK$!)k0hi4W> zI)Y`!N}QEGs;~9M%A2KITVHh2hxCKmFG@=@1Luo4{O*viP25dwBZfG99UGggu$nUmrrV5-GvW^RbS(sYq93j-F+jGd zslA(~U%51h<(1C}BFk}W*%urJt?wYf9F_7)PIT-4waLWh9!|0Px8!{8Nq}F^oI&;qgjL4a^s0_iaBfAe~=x(Ta*xfx_eT7sL+$uUxa?+=Qt;(|UcwRu;3+QIC|(b@C`SlI zeRr=zq#U!+JNeX59n4-%xfaW1Br@Q?WxciJ+){=AxLm_KXL+OwKv$)--)OxHaej-! zZsH$j(`&Hv>o}^(f1Y{pTZdZ|4q%h27!!>A=#}~MCEVy4ppoBF-u$U3IBACT@3SRi zf40EXKr$N9#aueVZVqWyC7bnT$Ryui#;B05WwwpF1pxgY#^BgzHDXwv%e=hNs6^sK-4a= zO2CiV4gUOZjMZmxZS4X3Vi<%`a%#-g%3p&(d)9*s`IYYPqN?u_L$ivT#k`p*)<(h z&XL=OhN4(js8Np}c=qSrBUOEfT;EpzA=W*HwSXd%Kd1Og%s`t+6$1_6r~LA>lPAJs zJ#!RkrSeeMIs4w9tOGb#S!kX`P{h+WX4b88y~fA5xfn{*_fKt&GQgf$?9>XE8`6K;V|_kfWiPpxYqeRXDb|{kZ0;kY*4iXS)XMEvLE(n=Y{f9tPt&1ct`j2ZhK4 z+i3j1Um;)f{+0E{_t0d{Kv(?e;pfy===n=^^(m`_&##6_Lf;YYu9 zgKIp!Fx`R1u%&8ML47rNwgM5W8{SaMYFRyE zl|cp6LVNfU!A7875l0>=`)Ejfl62-xO26$N@3|pyj!R>^Iai7^se6Q}=Cog8n&N{z z5A}wUpx!AlJVoSFr@+-H1W%`2C9G``uHV? z)}{{C^Xw#VeOad~5bk)L%30D9d~)bedq*+FM%zJpv2dmM93tp#cHQ7 zNq>X5@;v;JVrqpDprmqfBg92mq>6~Em z0{+p1Q>6HU6azuLrLrpur?p2h8n-C5Ve4BFfVS*uFVD>=9eeou11OlSDuIkYfXZbo zIb}g575i33$#FrDWW3IwV{c`fOVBeBYwK%5CDra^bCeAHKS1}U#YLR!ZqGbk`vF}M zMbxH=gVRKjg;}eT5kopvkQPA);X3p+V@IdRNKvNi_N1$sR&zO9P6lQB#|V5gtx6#$ z1$BxbC5j5dbeNlb9nv}sl)};Gn&)yX6u@$Du8eQ)vZBZe1uC|4^+y}5T^+0-57m~w zB(1pX7nIsegfm%gM2LO@@5{4(mna*nNoSdp`!r&@7A2uzY!2CI>4Ml6BKHwj9SK@a zAzbSFq_vvDu3tI;ek};WQXV9jTsW~^U;fNpZuDsJJ|HMO zh>A2>_f=hKH)bJBCHL`!Gt!t#s7KTy^ua~A~D(@efLySNP|jiKop9$ zT-Y}PGn1vN--Doj_rb016Yf>W+K#&y@d$G#%q5|OrR@td{py*kDw0%Ek1B8yXepBq zWeFxpJR7-A;ZqGZu-6l4rMDT$5sm4pPHB~A{J-~>ny6!_%A7l~Y-6Q4fN>@Ky}~@Z zIGVVeoM(>BC8qwt)O_T94(Pe0W2tr&uX38yy1gH_xVtKoUVzm}y>)53#j;lUZ4Ou6 z=3u(wcXVvc^Ywsa2v8REF;FKz9phTt-)?t!Ln)P<*N`x}DKN;k^nj{M(4k2-*~!Uw zh;ZbOtoi1HVZ>0-HKM{ID&J}{F1o40~XmV1;idXi~YVuINnw<%9xlmNG%6ot;9c}3(tDqnVBP4R-hSXPndMQ9QCyLbbp zyNN`|;z$aSDiyLw!UlQn3b@LPX3G_X`n&n^KJAPP(1AD1vmkj~0@O1I&B^@jLNonc zjcZ7Ff>vbXIZ$1Brsc~h)}0YcwV{+2oJuUFbp9Uaa?OkL$5Tqg4Q0Gl^Mc#)-M#x6 z0F!M)^1cy7NEEnImBTM5Zzp0nHfXU#fewBjLItb-s)5$fb)*`jyGT_#Uri|}qmM>O z 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≶M9Zv|5`G?V+t`dH%WEMXqpk;_3Hk#c)5bow}^>GHdOg=@5pYx=49b13Ly zrJynzDRebu8rnRSaDCBo@|9g53n?-Toj%;)7@=UY|Noy}Ma{<^CTZW`I9PGat{6t2 zaDw4J3oUfqrNwG{*q4kXjQO#)d%E?I`6unq0@g?R`EPa45Y|xpiRX?D^@^QqfPjrp z`1!tA9;wNGs_VH%HtUBo8*1_;v~g)avtfdTTKYQ+w|_T@R1|@!z4MWbhw@XQ#{r8n zFBZwGL~*S&Epds65DN=S9LDmC%OD``N?Ja3mq@-KYHmwkg<5GJXlu`C1U~hF;}GUt zEV_svDDRB0pxY;h0iVB6!+t9MoPjoUN2{tnNvmp71!_;3|F6OefCDX3EgVYSHa&Y~ zU}M_~aPglu-?Am;VW9ar%IVbGkq@`{Tq5wAt!;iU^4x0?c1udN{X&%ux4V&|KJ4W8 z^-G%6%-Mk6r|NGgPt?6Gz6|&!zRxhaV4(F`GZ8rK4j__!PX?Q7^;*CQ1mh5%DvR6C z?e!IxGMT8~xw^^9NiPO6=pQ@SRODn~Fsq8jD|VmScW#=CFmzog>dWa9ISWyD>bX6* zxnZ#2TwN0;af`pj^X|5h-UR+^#wtJ!B@tKiK!pf5VjK5!fZLt zzX!?qwZ#;g@k9fI%Zc#zkaZg@VAO57d!5O3Ue&0UhOx8iALeb!OI zRvYFgz{G^aMMxIXA9Q8%Ks(ns{Ng8LwsDMRXV9_!HbeTZg#-D*^A&&kWc>8s7s|rI z=ynSoO>Z_is~m>%blt}gX#It_>e2=$ntV|mjceXzzfgYM^uWLH4|qn@T1Vx$y+(mB zr_oTl_0pJ8ZR}4L)pN;gX0*r7gHMr7oprWF%6?*dA?da-61JtJNHWwP^#36TIN#Kl zHX65H`VqI9GB?_ee-?H!Yb?FpyYadu!+UaImNKBnpF_sZf6ay)B7}^R1hodXNP?eK z4UhCNG=>^Ra(w)t-DekO(;#W^pCZ0-I00f84I3?O?7O zB%x)J$UIIl{lRxlFHDbkes}4Xh27aeZ@lufb-e26$_f|NxU&YtVUJG#2x>BxrM_VU z1LCx!(BL?8gDF{Vq$J)xNc>yL)$=)7I*g|%)(&0-;j8CsUSvGa_^S6DVMpH zb8v0T>G{!ohHICj*>1fftNM+zZtws0KCZLv(IK>C_QT1EH@fD(8$2iPv~!>Y4cV!P zSZxtr!>L43HPE+4<>ftO;-5eywKK$aj&E__@NZF$Ub2O545&GURXRcHZf+@4Q*sxY zWp376swn?@b?YH5czxG41HZOjt)n5ymnfWVn}~l0v!W9f09Qb$zl@4>j!2BD$PIWy zG%tHq1co&qIS~ddbB3;u@9Dn~xdsYnr5s8^`W*i3m@VDEnOB&F?o#)Rs5v1eUah$w>#9 z(>0sd(bH1S1!0KMO_Fm9-(30B*tAvEi!I8bj@kN6Z10~`=5`eh*Oh@TSgc~GARo=W z<9@k$y19A1xpq3jbDRG4LD38!4XW&4?>FThiiaoIiVSTRo?|YzPPb-muv!>myEIOW zt#-bt4&U((ZdDWewL`sy(~|m2`BN@QF+Q{|G9ZCrd6ta$KC*E*TQ_G)_3NXw*H*CY zbEL^@$wN>XGaLNe4bu&0*GJMUg5zS=CN)LQyqHShcMq=mcw_4h9+%ozHC=V~`$%?N z`DWW#&TppMgR}4%!g!nK9J8-_y1Mk=F&oUrC@E68`W@5@I(HpHbiw(p1ld9~Keub^ z`qq-^lE(GMES@?`16xSt_yAA?b$A0;omip zd;&xiYAZP+=TTDO@|)ZHN*1!_{_wQ@i@zy5-UG{`HCbB7dqN5AgmRL@R~5 z-KAmZe7J3gow^U;9@e_R+QBj&j{H=={FCM3!&hwmwI9#NDh>OjBmRdo%0A!wRKaXY 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