class StableMarriageMatcher: def __init__(self, men, women): self.matching = Matching(men, women) pass def find_matching(self): self.gale_shapley() def gale_shapley(self): self.matching.unmatch_all() free_men = deque(self.matching.matches_men.keys()) men_proposition_list = {} for key in self.matching.matches_men: men_proposition_list[key] = 0 while free_men: m = free_men.popleft() w = self.matching.men_ranks[m][men_proposition_list[m]] men_proposition_list[m] += 1 if self.matching.woman_is_free(w): self.matching.match_pair(m, w) elif self.matching.woman_prefers_new_match(w, m): old_man = self.matching.matches_women[w] self.matching.unmatch_pair(old_man, w) free_men.append(old_man) self.matching.match_pair(m, w) else: free_men.append(m)
def solve(self, optimal="suitor"): """ Solve the instance of SM using either the suitor- or reviewer-oriented Gale-Shapley algorithm. Return the matching. """ self.matching = Matching( stable_marriage(self.suitors, self.reviewers, optimal)) return self.matching
def left_stitch(self, a, b, flag=None): if flag == 1: m = Matching('./lib/lib1.jpg', './lib/lib2.jpg') m.ransac(100) H_inv = m.H H = self.matcher.match(a, b, 'left') H_inv = np.linalg.inv(H) # find top left point for offset calculation. tl = np.dot(H_inv, np.array([0, 0, 1])) tl = tl / tl[-1] H_inv[0][-1] += abs(tl[0]) H_inv[1][-1] += abs(tl[1]) # find down right for size calculation. w, h = a.shape[1], a.shape[0] dr = np.dot(H_inv, np.array([w, h, 1])) dsize = (int(dr[0]) + abs(int(tl[0])), int(dr[1]) + abs(int(tl[1]))) # warp a into b's view and put them together. merge = cv2.warpPerspective(a, H_inv, dsize) fig = plt.figure() ax1 = fig.add_subplot(1, 2, 1) plt.imshow(merge) ax2 = fig.add_subplot(1, 2, 2) merge[abs(int(tl[1])):b.shape[0] + abs(int(tl[1])), abs(int(tl[0])):b.shape[1] + abs(int(tl[0])), :] = b plt.imshow(merge) plt.show() offset = (abs(int(tl[0])), abs(int(tl[1]))) return merge, offset
def repair(self, P, Q, inter, ins=None, args=None, entryfnc=None, ignoreio=False, ignoreret=False): self.starttime = time.time() self.vignore = set() if ignoreio: self.vignore |= set([VAR_IN, VAR_OUT]) # (1) Check struct match M = Matching(verbose=self.verbose) self.sm = M.match_struct(P, Q) if self.sm is None: raise StructMismatch('') # (2) Obtain trace of P self.trace = self.gettrace(P, inter, ins, args, entryfnc) # (3) Repair each fnc sepearately self.inter = inter() results = {} for fnc1 in P.getfncs(): fnc2 = Q.getfnc(fnc1.name) results[fnc1.name] = (self.repair_fnc(fnc1, fnc2) + (self.sm[fnc1.name],)) self.debug('total time: %.3f', round(time.time() - self.starttime, 3)) return results
def match_couple_hdom(self): ''' Certaines personnes se déclarent en couple avec quelqu'un ne vivant pas au domicile, on les reconstruit ici. Cette étape peut s'assimiler à de la fermeture de l'échantillon. On séléctionne les individus qui se déclare en couple avec quelqu'un hors du domicile. On match mariés,pacsé d'un côté et sans contrat de l'autre. Dit autrement, si on ne trouve pas de partenaire à une personne mariée ou pacsé on change son statut de couple. Comme pour les liens parents-enfants, on néglige ici la possibilité que le conjoint soit hors champ (étrange, prison, casernes, etc). Calcul aussi la variable ind['nb_enf'] ''' ind = self.ind couple_hdom = ind['couple']==2 # ind[couple_hdom].groupby(['etamatri','sexe']) # vu leur nombre, on regroupe pacsé et mariés dans le même sac ind.ix[(couple_hdom) & (ind['etamatri']==5), 'etamatri'] = 2 # note que du coup, on cherche un partenaire de pacs parmi le sexe opposé. Il y a une petite par technique là dedans qui fait qu'on # ne gère pas les couples homosexuels #pour avoir un age plus "continu" sans gap d'une année de naissance à l'autre age = self.survey_date/100 - ind['anais'] ind['age'] = (12*age + 11 - ind['mnais'])/12 ## nb d'enfant nb_enf_mere= ind.groupby('mere').size() nb_enf_pere = ind.groupby('pere').size() enf_tot = pd.concat([nb_enf_mere, nb_enf_pere], axis=1) enf_tot = enf_tot.sum(axis=1) #comme enf_tot a le bon index on fait ind['nb_enf'] = enf_tot ind['nb_enf'] = ind['nb_enf'].fillna(0) men_contrat = couple_hdom & (ind['etamatri'].isin([2,5])) & (ind['sexe']==1) women_contrat = couple_hdom & (ind['etamatri'].isin([2,5])) & (ind['sexe']==2) men_libre = couple_hdom & (~ind['etamatri'].isin([2,5])) & (ind['sexe']==1) women_libre = couple_hdom & (~ind['etamatri'].isin([2,5])) & (ind['sexe']==2) var_match = ['age','findet','nb_enf'] #,'classif','dip6' score = "- 0.4893 * other.age + 0.0131 * other.age **2 - 0.0001 * other.age **3 "\ " + 0.0467 * (other.age - age) - 0.0189 * (other.age - age) **2 + 0.0003 * (other.age - age) **3 " \ " + 0.05 * (other.findet - findet) - 0.5 * (other.nb_enf - nb_enf) **2 " match_contrat = Matching(ind.ix[women_contrat, var_match], ind.ix[men_contrat, var_match], score) match_found = match_contrat.evaluate(orderby=None, method='cells') ind.ix[match_found.values,'conj'] = match_found.index ind.ix[match_found.index,'conj'] = match_found.values match_libre = Matching(ind.ix[women_libre, var_match], ind.ix[men_libre, var_match], score) match_found = match_libre.evaluate(orderby=None, method='cells') ind.ix[match_found.values,'conj'] = match_found.index ind.ix[match_found.index,'conj'] = match_found.values ind.ix[men_libre & ~notnull(ind['conj']),['etamatri','couple']] = [1,3] ind.ix[women_libre & ~notnull(ind['conj']),['etamatri','couple']] = [1,3] #on corrige là, les innocents qui se disent mariés et pas en couple. ind.ix[ind['etamatri'].isin([2,5]) & ~notnull(ind['conj']),['etamatri','couple']] = [3,3] self.ind = ind self.drop_variable({'ind':['couple','age']})
def test_repr(): """ Check that a Matching is represented by a normal dictionary. """ matching = Matching() assert repr(matching) == "{}" matching = Matching(dictionary) assert repr(matching) == str(dictionary)
def matching(): if request.method == 'POST': content = request.get_json(force=True) payload = dict() payload["user_ids"] = content.get('user_ids') payload["desc"] = content.get('descriptions') matcher = Matching(payload) matches = matcher.get_matches() return jsonify(matches)
def test_init(): """Make an instance of the Matching class and check their attributes are correct.""" matching = Matching() assert matching == {} matching = Matching(dictionary) assert matching == dictionary
def initObj(self): # 设置大小,用于背景图片的缩放 self.gameNet = GameNet(self) self.gameNet.connectToServer() self.menu = Menu((self.width, self.height), self) self.rules = Rules(self.width, self.height) self.setLevel = SetLevel(self.width, self.height) self.matching = Matching((self.width, self.height), self) self.game = Game(self) # finish 界面的大小和游戏界面一样 self.finish = Finish((self.game.width, self.game.height))
def process_data(self,address,begin_time,end_time): ap_m = self.conn.select_data(address,begin_time,end_time) # 底图处理 if end_time == global_begin_time: #***与上一次底图进行比较,更新ap_mac(包含其中的无效化值) # 历史数据匹配 else: #**历史数据匹配 # match = Matching("信号类型0或1") # 匹配历史数据的时间范围 match.history_division("开始时间", "结束时间") # 匹配的结果 aps,result = match.match.history_matching(begin_time,end_time) #**两部分数据整合:ap_m和result return ap_m
def __init__(self, batch_size, encoder): super(Model, self).__init__() self.encoder = encoder n_classes = 3 # entailment, contradiction, neutral n_inputs = 4 * encoder.get_dim() words_dim = 0 # classifier: Multi-Layer Perceptron with 1 hidden layer of 512 hidden units # dnn_hidden_units = [512] dnn_hidden_units = 512 classifier = nn.Sequential(*[ nn.Linear(n_inputs, dnn_hidden_units), nn.ReLU(), nn.Linear(dnn_hidden_units, n_classes), ]) self.matching = Matching() self.classifier = classifier self.softmax = torch.nn.Softmax(dim=words_dim) self.net = nn.Sequential(*[ # Matching(), self.classifier, self.softmax, ])
def test_setitem_key_error(): """Check that a ValueError is raised if trying to add a new item to a Matching.""" matching = Matching(dictionary) with pytest.raises(ValueError): matching["foo"] = "bar"
def solve(self, optimal="student"): """Solve the instance of SA using either the student- or supervisor-optimal algorithm.""" self.matching = Matching( student_allocation(self.students, self.projects, self.supervisors, optimal)) return self.matching
def solve(self, optimal="resident"): """ Solve the instance of HR using either the resident- or hospital-oriented algorithm. Return the matching. """ self._matching = Matching( hospital_resident(self.residents, self.hospitals, optimal) ) return self.matching
def test_setitem_none(): """ Check can set item in Matching to be None. """ matching = Matching(dictionary) suitor = suitors[0] matching[suitor] = None assert matching[suitor] is None assert suitor.matching is None
def test_setitem_val_error(): """Check that a ValueError is raised if trying to set an item with some illegal new matching.""" matching = Matching(dictionary) suitor = suitors[0] new_match = [1, 2, 3] with pytest.raises(ValueError): matching[suitor] = new_match
def test_setitem_single(): """Check that a key in Matching can have its value changed to another Player instance.""" matching = Matching(dictionary) suitor, reviewer = suitors[0], reviewers[-1] matching[suitor] = reviewer assert matching[suitor] == reviewer assert suitor.matching == reviewer assert reviewer.matching == suitor
def test_setitem_multiple(): """ Check can set item in Matching to be a group of Player instances. """ matching = Matching(dictionary) suitor = suitors[0] new_match = reviewers[:-1] matching[suitor] = new_match assert set(matching[suitor]) == set(new_match) for rev in new_match: assert rev.matching == suitor
class NthPlayed: """ Condition to check if a condition is the nth card played """ def __init__(self, n, criteria): """ Initialize the condition with the value of n """ self.n = n self.playedFilter = ComparisonFilter(PLAYED, criteria) self.eventCondition = Matching(EVENT, criteria) def evaluate(self, context): """ Evaluate the condition """ return self.eventCondition.evaluate(context) and len(self.playedFilter.evaluate(context)) == self.n-1
def test_keys(): """ Check a Matching can have its `keys` accessed. """ matching = Matching() assert list(matching.keys()) == [] matching = Matching(dictionary) assert list(matching.keys()) == suitors
def test_values(): """ Check a Matching can have its `values` accessed. """ matching = Matching() assert list(matching.values()) == [] matching = Matching(dictionary) assert list(matching.values()) == reviewers
def repair(self, P, Q, inter, ins=None, args=None, entryfnc=None, ignoreio=False, ignoreret=False): self.starttime = time.time() self.vignore = set() if ignoreio: self.vignore |= set([VAR_IN, VAR_OUT]) # (1) Check struct match M = Matching(verbose=self.verbose) self.sm = M.match_struct(P, Q) if self.sm is None: raise StructMismatch('') # (2) Obtain trace of P self.trace = self.gettrace(P, inter, ins, args, entryfnc) # (3) Repair each fnc sepearately self.inter = inter() results = {} for fnc1 in P.getfncs(): fnc2 = Q.getfnc(fnc1.name) results[fnc1.name] = (self.repair_fnc(fnc1, fnc2) + (self.sm[fnc1.name], )) self.debug('total time: %.3f', round(time.time() - self.starttime, 3)) return results
def score(path_predictions, path_groundtruth, path_output, iou_threshold=.4): assert (iou_threshold < 1 and iou_threshold > 0) ttime = time.time() boxes_dict = {} pchips = [] stclasses = [] num_preds = 0 for file in tqdm(os.listdir(path_predictions)): fname = file.split(".txt")[0] pchips.append(fname) with open(path_predictions + file, 'r') as f: arr = np.array(list(csv.reader(f, delimiter=" "))) if arr.shape[0] == 0: #If the file is empty, we fill it in with an array of zeros boxes_dict[fname] = np.array([[0, 0, 0, 0, 0, 0]]) num_preds += 1 else: arr = arr[:, :6].astype(np.float64) threshold = iou_threshold arr = arr[arr[:, 5] > threshold] stclasses += list(arr[:, 4]) num_preds += arr.shape[0] if np.any(arr[:, :4] < 0): raise ValueError('Bounding boxes cannot be negative.') if np.any(arr[:, 5] < 0) or np.any(arr[:, 5] > 1): raise ValueError( 'Confidence scores should be between 0 and 1.') boxes_dict[fname] = arr[:, :6] pchips = sorted(pchips) stclasses = np.unique(stclasses).astype(np.int64) gt_coords, gt_chips, gt_classes = get_labels(path_groundtruth) gt_coords = gt_coords[gt_chips == '5.tif'] gt_classes = gt_classes[gt_chips == '5.tif'].astype(np.int64) gt_chips = gt_chips[gt_chips == '5.tif'] gt_unique = np.unique(gt_classes.astype(np.int64)) print(gt_unique) max_gt_cls = 100 if set(pchips).issubset(set(gt_unique)): raise ValueError( 'The prediction files {%s} are not in the ground truth.' % str(set(pchips) - (set(gt_unique)))) print("Number of Predictions: %d" % num_preds) print("Number of GT: %d" % np.sum(gt_classes.shape)) per_file_class_data = {} for i in gt_unique: per_file_class_data[i] = [[], []] num_gt_per_cls = np.zeros((max_gt_cls)) for file_ind in range(len(pchips)): print(pchips[file_ind]) det_box = boxes_dict[pchips[file_ind]][:, :4] det_scores = boxes_dict[pchips[file_ind]][:, 5] det_cls = boxes_dict[pchips[file_ind]][:, 4] gt_box = gt_coords[(gt_chips == pchips[file_ind]).flatten()] gt_cls = gt_classes[(gt_chips == pchips[file_ind])] for i in gt_unique: s = det_scores[det_cls == i] ssort = np.argsort(s)[::-1] per_file_class_data[i][0] += s[ssort].tolist() gt_box_i_cls = gt_box[gt_cls == i].flatten().tolist() det_box_i_cls = det_box[det_cls == i] det_box_i_cls = det_box_i_cls[ssort].flatten().tolist() gt_rects = convert_to_rectangle_list(gt_box_i_cls) rects = convert_to_rectangle_list(det_box_i_cls) matching = Matching(gt_rects, rects) rects_matched, gt_matched = matching.greedy_match(iou_threshold) #we aggregate confidence scores, rectangles, and num_gt across classes #per_file_class_data[i][0] += det_scores[det_cls == i].tolist() per_file_class_data[i][1] += rects_matched num_gt_per_cls[i] += len(gt_matched) average_precision_per_class = np.ones(max_gt_cls) * float('nan') per_class_p = np.ones(max_gt_cls) * float('nan') per_class_r = np.ones(max_gt_cls) * float('nan') for i in gt_unique: scores = np.array(per_file_class_data[i][0]) rects_matched = np.array(per_file_class_data[i][1]) if num_gt_per_cls[i] != 0: sorted_indices = np.argsort(scores)[::-1] tp_sum = np.cumsum(rects_matched[sorted_indices]) fp_sum = np.cumsum(np.logical_not(rects_matched[sorted_indices])) precision = tp_sum / (tp_sum + fp_sum + np.spacing(1)) recall = tp_sum / num_gt_per_cls[i] per_class_p[i] = np.sum(rects_matched) / len(rects_matched) per_class_r[i] = np.sum(rects_matched) / num_gt_per_cls[i] ap = ap_from_pr(precision, recall) else: ap = float('nan') average_precision_per_class[i] = ap #metric splits metric_keys = [ 'map', 'map/small', 'map/medium', 'map/large', 'map/common', 'map/rare' ] splits = { 'map/small': [ 17, 18, 19, 20, 21, 23, 24, 26, 27, 28, 32, 41, 60, 62, 63, 64, 65, 66, 91 ], 'map/medium': [ 11, 12, 15, 25, 29, 33, 34, 35, 36, 37, 38, 42, 44, 47, 50, 53, 56, 59, 61, 71, 72, 73, 76, 84, 86, 93, 94 ], 'map/large': [13, 40, 45, 49, 51, 52, 54, 55, 57, 74, 77, 79, 83, 89], 'map/common': [ 13, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 34, 35, 41, 47, 60, 63, 64, 71, 72, 73, 76, 77, 79, 83, 86, 89, 91 ], 'map/rare': [ 11, 12, 15, 29, 32, 33, 36, 37, 38, 40, 42, 44, 45, 49, 50, 51, 52, 53, 54, 55, 56, 57, 59, 61, 62, 65, 66, 74, 84, 93, 94 ] } vals = {} vals['map'] = np.nanmean(average_precision_per_class) vals['map_score'] = np.nanmean(per_class_p) vals['mar_score'] = np.nanmean(per_class_r) for i in splits.keys(): vals[i] = np.nanmean(average_precision_per_class[splits[i]]) for i in gt_unique: vals[int(i)] = average_precision_per_class[int(i)] vals['f1'] = 2 / ((1 / (np.spacing(1) + vals['map_score'])) + (1 / (np.spacing(1) + vals['mar_score']))) print("mAP: %f | mAP score: %f | mAR: %f | F1: %f" % (vals['map'], vals['map_score'], vals['mar_score'], vals['f1'])) with open(path_output + '/score.txt', 'w') as f: f.write(str("%.4f" % vals['map'])) result = [] with open(path_output + '/metrics.txt', 'w') as f: for key in vals.keys(): f.write("%s %.4f\n" % (str(key), vals[key])) result.append( str(key) + " " + str(round(float(vals[key]), 4)) + "\n") result = sorted(result) print("Final time: %s" % str(time.time() - ttime)) return result
def solve(self): self._matching = Matching( mentor_mentee(self.mentees, self.mentors, "mentor")) return self.matching
def score(path_predictions, path_groundtruth, path_output, iou_threshold=.5): """ Compute metrics on a number of prediction files, given a folder of prediction files and a ground truth. Primary metric is mean average precision (mAP). Args: path_predictions: a folder path of prediction files. Prediction files should have filename format 'XYZ.tif.txt', where 'XYZ.tif' is the xView TIFF file being predicted on. Prediction files should be in space-delimited csv format, with each line like (xmin ymin xmax ymax class_prediction score_prediction) path_groundtruth: a file path to a single ground truth geojson path_output: a folder path for output scoring files iou_threshold: a float between 0 and 1 indicating the percentage iou required to count a prediction as a true positive Outputs: Writes two files to the 'path_output' parameter folder: 'score.txt' and 'metrics.txt' 'score.txt' contains a single floating point value output: mAP 'metrics.txt' contains the remaining metrics in per-line format (metric/class_num: score_float) Raises: ValueError: if there are files in the prediction folder that are not in the ground truth geojson. EG a prediction file is titled '15.tif.txt', but the file '15.tif' is not in the ground truth. """ assert (iou_threshold < 1 and iou_threshold > 0) ttime = time.time() boxes_dict = {} pchips = [] stclasses = [] num_preds = 0 for file in tqdm(os.listdir(path_predictions)): fname = file.split(".txt")[0] pchips.append(fname) with open(path_predictions + file, 'r') as f: arr = np.array(list(csv.reader(f, delimiter=" "))) arr = arr[:, :6].astype(np.float64) threshold = 0 arr = arr[arr[:, 5] > threshold] stclasses += list(arr[:, 4]) num_preds += arr.shape[0] if np.any(arr[:, :4] < 0): raise ValueError('Bounding boxes cannot be negative.') boxes_dict[fname] = arr[:, :6] pchips = sorted(pchips) stclasses = np.unique(stclasses).astype(np.int64) gt_coords, gt_chips, gt_classes = get_labels(path_groundtruth) gt_unique = np.unique(gt_classes.astype(np.int64)) max_gt_cls = 100 if set(pchips).issubset(set(gt_unique)): raise ValueError( 'The prediction files {%s} are not in the ground truth.' % str(set(pchips) - (set(gt_unique)))) print("Number of Predictions: %d" % num_preds) print("Number of GT: %d" % np.sum(gt_classes.shape)) per_file_class_data = {} for i in gt_unique: per_file_class_data[i] = [[], []] num_gt_per_cls = np.zeros((max_gt_cls)) for file_ind in range(len(pchips)): print(pchips[file_ind]) det_box = boxes_dict[pchips[file_ind]][:, :4] det_scores = boxes_dict[pchips[file_ind]][:, 5] det_cls = boxes_dict[pchips[file_ind]][:, 4] gt_box = gt_coords[(gt_chips == pchips[file_ind]).flatten()] gt_cls = gt_classes[(gt_chips == pchips[file_ind])] for i in gt_unique: gt_box_i_cls = gt_box[gt_cls == i].flatten().tolist() det_box_i_cls = det_box[det_cls == i].flatten().tolist() gt_rects = convert_to_rectangle_list(gt_box_i_cls) rects = convert_to_rectangle_list(det_box_i_cls) matching = Matching(gt_rects, rects) rects_matched, gt_matched = matching.greedy_match(iou_threshold) #we aggregate confidence scores, rectangles, and num_gt across classes per_file_class_data[i][0] += det_scores[det_cls == i].tolist() per_file_class_data[i][1] += rects_matched num_gt_per_cls[i] += len(gt_matched) average_precision_per_class = np.ones(max_gt_cls) * float('nan') per_class_p = np.ones(max_gt_cls) * float('nan') per_class_r = np.ones(max_gt_cls) * float('nan') for i in gt_unique: scores = np.array(per_file_class_data[i][0]) rects_matched = np.array(per_file_class_data[i][1]) if num_gt_per_cls[i] != 0: sorted_indices = np.argsort(scores)[::-1] tp_sum = np.cumsum(rects_matched[sorted_indices]) fp_sum = np.cumsum(np.logical_not(rects_matched[sorted_indices])) precision = tp_sum / (tp_sum + fp_sum + np.spacing(1)) recall = tp_sum / num_gt_per_cls[i] per_class_p[i] = np.sum(rects_matched) / len(rects_matched) per_class_r[i] = np.sum(rects_matched) / num_gt_per_cls[i] ap = ap_from_pr(precision, recall) else: ap = float('nan') average_precision_per_class[i] = ap #metric splits metric_keys = [ 'map', 'map/small', 'map/medium', 'map/large', 'map/common', 'map/rare' ] splits = { 'map/small': [ 17, 18, 19, 20, 21, 23, 24, 26, 27, 28, 32, 41, 60, 62, 63, 64, 65, 66, 91 ], 'map/medium': [ 11, 12, 15, 25, 29, 33, 34, 35, 36, 37, 38, 42, 44, 47, 50, 53, 56, 59, 61, 71, 72, 73, 76, 84, 86, 93, 94 ], 'map/large': [13, 40, 45, 49, 51, 52, 54, 55, 57, 74, 77, 79, 83, 89], 'map/common': [ 13, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 34, 35, 41, 47, 60, 63, 64, 71, 72, 73, 76, 77, 79, 83, 86, 89, 91 ], 'map/rare': [ 11, 12, 15, 29, 32, 33, 36, 37, 38, 40, 42, 44, 45, 49, 50, 51, 52, 53, 54, 55, 56, 57, 59, 61, 62, 65, 66, 74, 84, 93, 94 ] } vals = {} vals['map'] = np.nanmean(average_precision_per_class) vals['map_score'] = np.nanmean(per_class_p) vals['mar_score'] = np.nanmean(per_class_r) for i in splits.keys(): vals[i] = np.nanmean(average_precision_per_class[splits[i]]) for i in gt_unique: vals[int(i)] = average_precision_per_class[int(i)] vals['f1'] = 2 / ((1 / (np.spacing(1) + vals['map_score'])) + (1 / (np.spacing(1) + vals['mar_score']))) print("mAP: %f | mAP score: %f | mAR: %f | F1: %f" % (vals['map'], vals['map_score'], vals['mar_score'], vals['f1'])) with open(path_output + '/score.txt', 'w') as f: f.write(str("%.8f" % vals['map'])) with open(path_output + '/metrics.txt', 'w') as f: for key in vals.keys(): f.write("%s %f\n" % (str(key), vals[key])) print("Final time: %s" % str(time.time() - ttime))
class StableMarriage(BaseGame): """ A class for solving instances of the stable marriage problem (SM). Parameters ---------- suitors : list of Player The suitors in the game. Each suitor must rank all elements in ``reviewers``. reviewers : list of Player The reviewers in the game. Each reviewer must rank all elements in ``suitors``. Attributes ---------- matching : Matching or None Once the game is solved, a matching is available. This uses the suitors and reviewers as keys and values, respectively, in a ``Matching`` object. Initialises as `None`. blocking_pairs : list of (Player, Player) The suitor-reviewer pairs that both prefer one another to their current match. Initialises as ``None``. """ def __init__(self, suitors, reviewers): suitors, reviewers = copy.deepcopy([suitors, reviewers]) self.suitors = suitors self.reviewers = reviewers super().__init__() self._check_inputs() @classmethod def create_from_dictionaries(cls, suitor_prefs, reviewer_prefs): """ Create an instance of SM from two preference dictionaries. """ suitors, reviewers = _make_players(suitor_prefs, reviewer_prefs) game = cls(suitors, reviewers) return game def solve(self, optimal="suitor"): """ Solve the instance of SM using either the suitor- or reviewer-oriented Gale-Shapley algorithm. Return the matching. """ self.matching = Matching( stable_marriage(self.suitors, self.reviewers, optimal)) return self.matching def check_stability(self): """ Check for the existence of any blocking pairs in the current matching, thus determining the stability of the matching. """ blocking_pairs = [] for suitor in self.suitors: for reviewer in self.reviewers: if suitor.prefers(reviewer, suitor.matching) and reviewer.prefers( suitor, reviewer.matching): blocking_pairs.append((suitor, reviewer)) self.blocking_pairs = blocking_pairs return not any(blocking_pairs) def check_validity(self): """ Check whether the current matching is valid. """ self._check_all_matched() self._check_matching_consistent() return True def _check_all_matched(self): """ Check everyone has a match. """ errors = [] for player in self.suitors + self.reviewers: if player.matching is None: errors.append(ValueError(f"{player} is unmatched.")) if player not in list(self.matching.keys()) + list( self.matching.values()): errors.append( ValueError(f"{player} does not appear in matching.")) if errors: raise Exception(*errors) return True def _check_matching_consistent(self): """ Check that the game matching is consistent with the players. """ errors = [] matching = self.matching for suitor in self.suitors: if suitor.matching != matching[suitor]: errors.append( ValueError( f"{suitor} is matched to {suitor.matching} but matching" f" says {matching[suitor]}.")) for reviewer in self.reviewers: suitor = [s for s in matching if matching[s] == reviewer][0] if reviewer.matching != suitor: errors.append( ValueError( f"{reviewer} is matched to {reviewer.matching} but " f"matching says {suitor}.")) if errors: raise Exception(*errors) return True def _check_inputs(self): """ Raise an error if any of the conditions of the game have been broken. """ self._check_num_players() for suitor in self.suitors: self._check_player_ranks(suitor) for reviewer in self.reviewers: self._check_player_ranks(reviewer) def _check_num_players(self): """ Check that the number of suitors and reviewers are equal. """ if len(self.suitors) != len(self.reviewers): raise ValueError( "There must be an equal number of suitors and reviewers.") return True def _check_player_ranks(self, player): """ Check that a player has ranked all of the other group. """ others = self.reviewers if player in self.suitors else self.suitors if set(player.prefs) != set(others): raise ValueError( "Every player must rank each name from the other group. " f"{player}: {player.prefs} != {others}") return True
def solve(self): """Solve the instance of SR using Irving's algorithm. Return the matching.""" self.matching = Matching(stable_roommates(self.players)) return self.matching
class StableRoommates(BaseGame): """A class for solving instances of the stable roommates problem (SR). Parameters ---------- players : list of Player The players in the game. Each must rank all other players. Attributes ---------- matching : Matching or None Once the game is solved, a matching is available. This uses the players as keys and values in a ``Matching`` object. Initialises as ``None``. """ def __init__(self, players): players = copy.deepcopy(players) self.players = players super().__init__() self.check_inputs() @classmethod def create_from_dictionary(cls, player_prefs): """ Create an instance of SR from a preference dictionary. """ players = _make_players(player_prefs) game = cls(players) return game def solve(self): """Solve the instance of SR using Irving's algorithm. Return the matching.""" self.matching = Matching(stable_roommates(self.players)) return self.matching def check_validity(self): """Check whether the current matching is valid. Raise `MatchingError` detailing the issues if not.""" issues = [] for player in self.players: issue = player.check_if_match_is_unacceptable(unmatched_okay=False) if issue: issues.append(issue) if issues: raise MatchingError(unmatched_players=issues) return True def check_stability(self): """Check for the existence of any blocking pairs in the current matching. Then the stability of the matching holds when there are no blocking pairs and all players have been matched.""" if None in self.matching.values(): return False blocking_pairs = [] for player in self.players: others = [p for p in self.players if p != player] for other in others: if (other, player) not in blocking_pairs: both_matched = player.matching and other.matching prefer_each_other = player.prefers( other, player.matching) and other.prefers( player, other.matching) if both_matched and prefer_each_other: blocking_pairs.append((player, other)) self.blocking_pairs = blocking_pairs return not any(blocking_pairs) def check_inputs(self): """ Check that all players have ranked all other players. """ for player in self.players: others = {p for p in self.players if p != player} if set(player.prefs) != others: raise ValueError( "Every player must rank all other players. " f"{player}: {player.prefs} is not a permutation of {others}" ) return True
def lien_parent_enfant_hdom(self): ''' Travail sur les liens parents-enfants. On regarde d'abord les variables utiles pour le matching puis on le réalise ''' men = self.men ind = self.ind ## info sur les enfants hors du domicile des parents par_look_enf = DataFrame() for k in range(1,13): k = str(k) var_hod = ['hodln','hodsex','hodan','hodco','hodip','hodenf', 'hodemp','hodcho','hodpri','hodniv'] var_hod_rename=['hodln','sexe','anais','couple','dip6','nb_enf', 'hodemp','hodcho','hodpri','hodniv'] var_hod_k = [var + k for var in var_hod] temp = men.ix[notnull(men[var_hod_k[0]]), ['id','pond']+var_hod_k] dict_rename = {} for num_varname in range(len(var_hod_rename)): dict_rename[var_hod_k[num_varname]] = var_hod_rename[num_varname] temp = temp.rename(columns=dict_rename) temp['situa'] = Series() temp['situa'][temp['hodemp']==1] = 1 temp['situa'][temp['hodemp']==2] = 5 temp['situa'][temp['hodcho']==1] = 4 temp['situa'][temp['hodcho']==2] = 6 temp['situa'][temp['hodcho']==3] = 3 temp['situa'][temp['hodcho']==4] = 7 temp['classif'] = Series() prive = temp['hodpri'].isin([1,2,3,4]) temp['classif'][prive] = temp['hodpri'][prive] temp['classif'][~prive] = temp['hodniv'][~prive] par_look_enf = par_look_enf.append(temp) var_parent = ["id","men","sexe","anais","cs42"] ind['gpar'] = ind['per1e'].isin([1,2]) | ind['mer1e'].isin([1,2]) info_pr = ind.ix[ind['lienpref']==0,var_parent] info_cj = ind.ix[ind['lienpref']==1,var_parent] var_parent_pr = ['id_pr'] + var_parent[1:] var_parent_pr[var_parent_pr.index('anais')] = 'anais_pr' var_parent_cj = [nom +'_cj' for nom in var_parent] # d'abord les peres puis les meres info_pr_pere = info_pr[info_pr['sexe']==1].rename(columns={'id':'pere', 'anais':'jepnais','gpar':'gparpat','cs42':'jepprof'}) info_cj_pere = info_cj[info_cj['sexe']==1].rename(columns={'id':'pere', 'anais':'jepnais','gpar':'gparpat','cs42':'jepprof'}) info_pere = info_pr_pere.append(info_cj_pere) cond1 = par_look_enf['hodln']==1 cond2 = par_look_enf['hodln']==2 cond3 = par_look_enf['hodln']==3 par_look_enf1 = merge(par_look_enf[cond1], info_pere, left_on='id', right_on='men', how = 'left') par_look_enf2 = merge(par_look_enf[cond2], info_pr_pere, left_on='id', right_on='men', how = 'left') par_look_enf3 = merge(par_look_enf[cond3], info_cj_pere, left_on='id', right_on='men', how = 'left') # d'abord les peres puis les meres info_pr_mere = info_pr[info_pr['sexe']==2].rename(columns={'id':'mere', 'anais':'jemnais','gpar':'gparmat','cs42':'jemprof'}) info_cj_mere = info_cj[info_cj['sexe']==2].rename(columns={'id':'mere', 'anais':'jemnais','gpar':'gparmat','cs42':'jemprof'}) info_mere = info_pr_mere.append(info_cj_mere) par_look_enf1 = merge(par_look_enf1, info_mere, left_on='id', right_on='men', how = 'left') par_look_enf2 = merge(par_look_enf2, info_pr_mere, left_on='id', right_on='men', how = 'left') par_look_enf3 = merge(par_look_enf3, info_cj_mere, left_on='id', right_on='men', how = 'left') par_look_enf = par_look_enf1.append(par_look_enf2).append(par_look_enf3) par_look_enf.index = range(len(par_look_enf)) ## info sur les parents hors du domicile des enfants cond_enf_look_par = (ind['per1e']==2) | (ind['mer1e']==2) enf_look_par = ind[cond_enf_look_par] # Remarque: avant on mettait à zéro les valeurs quand on ne cherche pas le parent, maintenant # on part du principe qu'on fait les choses assez minutieusement enf_look_par['dip6'] = Series() enf_look_par['dip6'][enf_look_par['diplome']>=30] = 5 enf_look_par['dip6'][enf_look_par['diplome']>=41] = 4 enf_look_par['dip6'][enf_look_par['diplome']>=43] = 3 enf_look_par['dip6'][enf_look_par['diplome']>=50] = 2 enf_look_par['dip6'][enf_look_par['diplome']>=60] = 1 enf_look_par['classif2'] = enf_look_par['classif'] enf_look_par['classif2'][enf_look_par['classif'].isin([1,2,3])] = 4 enf_look_par['classif2'][enf_look_par['classif'].isin([4,5])] = 2 enf_look_par['classif2'][enf_look_par['classif'].isin([6,7])] = 1 enf_look_par['classif2'][enf_look_par['classif'].isin([8,9])] = 3 enf_look_par['classif'] = enf_look_par['classif2'] ## nb d'enfant nb_enf_mere_dom = ind.groupby('mere').size() nb_enf_pere_dom = ind.groupby('pere').size() nb_enf_mere_hdom = par_look_enf.groupby('mere').size() nb_enf_pere_hdom = par_look_enf.groupby('pere').size() enf_tot = pd.concat([nb_enf_mere_dom, nb_enf_pere_dom, nb_enf_mere_hdom, nb_enf_pere_hdom], axis=1) enf_tot = enf_tot.sum(axis=1) #comme enf_tot a le bon index on fait enf_look_par['nb_enf'] = enf_tot enf_look_par['nb_enf'] = enf_look_par['nb_enf'].fillna(0) #Note: Attention le score ne peut pas avoir n'importe quelle forme, il faut des espaces devant les mots, à la limite une parenthèse var_match = ['jepnais','jepprof','situa','nb_enf','anais','classif','couple','dip6', 'jemnais','jemprof','sexe'] #TODO: gerer les valeurs nulles, pour l'instant c'est très moche #TODO: avoir une bonne distance score = "- 1 * (other.anais - anais) **2 - 1.0 * (other.situa - situa) **2 - 0.5 * (other.sexe - sexe) **2 - 1.0 * (other.dip6 - dip6) \ **2 - 1.0 * (other.nb_enf - nb_enf) **2" # etape1 : deux parents vivants cond1_enf = (enf_look_par['per1e'] == 2) & (enf_look_par['mer1e'] == 2) cond1_par = notnull(par_look_enf['pere']) & notnull(par_look_enf['mere']) # TODO: si on fait les modif de variables plus tôt, on peut mettre directement par_look_enf1 #à cause du append plus haut, on prend en fait ici les premiers de par_look_enf match1 = Matching(enf_look_par.ix[cond1_enf, var_match], par_look_enf.ix[cond1_par, var_match], score) parent_found = match1.evaluate() ind.ix[parent_found.index, ['pere','mere']] = par_look_enf.ix[parent_found, ['pere','mere']] enf_look_par.ix[parent_found.index, ['pere','mere']] = par_look_enf.ix[parent_found, ['pere','mere']] cond2_enf = (~notnull(enf_look_par['mere'])) & (enf_look_par['mer1e'] == 2) cond2_par = ~par_look_enf.index.isin(parent_found) & notnull(par_look_enf['mere']) match2 = Matching(enf_look_par.ix[cond2_enf, var_match], par_look_enf.ix[cond2_par, var_match], score) parent_found2 = match2.evaluate() ind.ix[parent_found2.index, ['mere']] = par_look_enf.ix[parent_found2, ['mere']] parent_found = parent_found.append(parent_found2, True) enf_look_par.ix[parent_found2.index, ['pere','mere']] = par_look_enf.ix[parent_found2, ['pere','mere']] cond3_enf = (~notnull(enf_look_par['pere'])) & (enf_look_par['per1e'] == 2) cond3_par = ~par_look_enf.index.isin(parent_found) & notnull(par_look_enf['pere']) # TODO: changer le score pour avoir un lien entre pere et mere plus évident match3 = Matching(enf_look_par.ix[cond3_enf, var_match], par_look_enf.ix[cond3_par, var_match], score) parent_found3 = match3.evaluate() ind.ix[parent_found3.index, ['pere']] = par_look_enf.ix[parent_found3, ['pere']] # Temps de calcul approximatif : 15 secondes, je laisse là juste pour voir les évolution du temps de calcul par la suite # mais il faudra supprimer un jour # match = Matching(enf_look_par[var_match], par_look_enf[var_match], score) # match.evaluate() self.ind = ind pdb.set_trace()
def matching_par_enf(self): ''' Matching des parents et des enfants hors du domicile ''' ind = self.ind par_look_enf = self.par_look_enf ## info sur les parents hors du domicile des enfants cond_enf_look_par = (ind['per1e']==2) | (ind['mer1e']==2) enf_look_par = ind[cond_enf_look_par] # Remarque: avant on mettait à zéro les valeurs quand on ne cherche pas le parent, maintenant # on part du principe qu'on fait les choses assez minutieusement recode(enf_look_par, 'dip14', 'dip6', [[30,5], [41,4], [43,3], [50,2], [60,1]] , method='geq') recode(enf_look_par, 'classif', 'classif2', [ [[1,2,3],4], [[4,5],2], [[6,7],1], [[8,9], 3], [[10],0]], method='isin') enf_look_par['classif'] = enf_look_par['classif2'] ## nb d'enfant nb_enf_mere_dom = ind.groupby('mere').size() nb_enf_pere_dom = ind.groupby('pere').size() nb_enf_mere_hdom = par_look_enf.groupby('mere').size() nb_enf_pere_hdom = par_look_enf.groupby('pere').size() enf_tot = pd.concat([nb_enf_mere_dom, nb_enf_pere_dom, nb_enf_mere_hdom, nb_enf_pere_hdom], axis=1) enf_tot = enf_tot.sum(axis=1) #comme enf_tot a le bon index on fait enf_look_par['nb_enf'] = enf_tot enf_look_par['nb_enf'] = enf_look_par['nb_enf'].fillna(0) #Note: Attention le score ne peut pas avoir n'importe quelle forme, il faut des espaces devant les mots, à la limite une parenthèse var_match = ['jepnais','situa','nb_enf','anais','classif','couple','dip6', 'jemnais','jemprof','sexe'] #TODO: gerer les valeurs nulles, pour l'instant c'est très moche #TODO: avoir une bonne distance score = "- 1 * (other.anais - anais) **2 - 1.0 * (other.situa - situa) **2 - 0.5 * (other.sexe - sexe) **2 - 1.0 * (other.dip6 - dip6) \ **2 - 1.0 * (other.nb_enf - nb_enf) **2" # etape1 : deux parents vivants cond1_enf = (enf_look_par['per1e'] == 2) & (enf_look_par['mer1e'] == 2) cond1_par = notnull(par_look_enf['pere']) & notnull(par_look_enf['mere']) # TODO: si on fait les modif de variables plus tôt, on peut mettre directement par_look_enf1 #à cause du append plus haut, on prend en fait ici les premiers de par_look_enf match1 = Matching(enf_look_par.ix[cond1_enf, var_match], par_look_enf.ix[cond1_par, var_match], score) parent_found = match1.evaluate(orderby=None, method='cells') ind.ix[parent_found.index, ['pere','mere']] = par_look_enf.ix[parent_found, ['pere','mere']] enf_look_par.ix[parent_found.index, ['pere','mere']] = par_look_enf.ix[parent_found, ['pere','mere']] cond2_enf = (~notnull(enf_look_par['mere'])) & (enf_look_par['mer1e'] == 2) cond2_par = ~par_look_enf.index.isin(parent_found) & notnull(par_look_enf['mere']) match2 = Matching(enf_look_par.ix[cond2_enf, var_match], par_look_enf.ix[cond2_par, var_match], score) parent_found2 = match2.evaluate(orderby=None, method='cells') ind.ix[parent_found2.index, ['mere']] = par_look_enf.ix[parent_found2, ['mere']] enf_look_par.ix[parent_found2.index, ['pere','mere']] = par_look_enf.ix[parent_found2, ['pere','mere']] cond3_enf = (~notnull(enf_look_par['pere'])) & (enf_look_par['per1e'] == 2) cond3_par = ~par_look_enf.index.isin(parent_found) & notnull(par_look_enf['pere']) # TODO: changer le score pour avoir un lien entre pere et mere plus évident match3 = Matching(enf_look_par.ix[cond3_enf, var_match], par_look_enf.ix[cond3_par, var_match], score) parent_found3 = match3.evaluate(orderby=None, method='cells') ind.ix[parent_found3.index, ['pere']] = par_look_enf.ix[parent_found3, ['pere']] self.ind = ind self.drop_variable({'ind':['enf','per1e','mer1e','gpar'] + ['jepnais','jemnais','jemprof']})
def __init__(self, men, women): self.matching = Matching(men, women) pass
def test_is_stable(): men_ranks, women_ranks = init_preferences() matches = Matching(men_ranks, women_ranks) assert (matches.is_stable() is False) matches.match_pair('abe', 'ada') matches.match_pair('ben', 'bea') matches.match_pair('che', 'cee') assert (matches.is_stable() is True) matches = Matching(men_ranks, women_ranks) matches.match_pair('abe', 'bea') matches.match_pair('ben', 'ada') matches.match_pair('che', 'cee') assert (matches.is_stable() is False) print("is_stable: OK!")
def compute_average_precision_recall(groundtruth_coordinates, coordinates, iou_threshold): """Computes the average precision (AP) and average recall (AR). Args: groundtruth_info_dict: the groundtruth_info_dict holds all the groundtruth information for an evaluation dataset. The format of this groundtruth_info_dict is as follows: {'image_id_0': [xmin_0,ymin_0,xmax_0,ymax_0,...,xmin_N0,ymin_N0,xmax_N0,ymax_N0], ..., 'image_id_M': [xmin_0,ymin_0,xmax_0,ymax_0,...,xmin_NM,ymin_NM,xmax_NM,ymax_NM]}, where image_id_* is an image_id that has the groundtruth rectangles labeled. xmin_*,ymin_*,xmax_*,ymax_* is the top-left and bottom-right corners of one groundtruth rectangle. test_info_dict: the test_info_dict holds all the test information for an evaluation dataset. The format of this test_info_dict is the same as the above groundtruth_info_dict. iou_threshold_range: the IOU threshold range to compute the average precision (AP) and average recall (AR). For example: iou_threshold_range = [0.50:0.05:0.95] Returns: average_precision, average_recall, as well as the precision_recall_dict, where precision_recall_dict holds the full precision/recall information for each of the iou_threshold in the iou_threshold_range. Raises: ValueError: if the input groundtruth_info_dict and test_info_dict show inconsistent information. """ # Start to build up the Matching instances for each of the image_id_*, which # is to hold the IOU computation between the rectangle pairs for the same # image_id_*. matchings = {} if (len(groundtruth_coordinates) % 4 != 0) or (len(coordinates) % 4 != 0): raise ValueError( 'groundtruth_info_dict and test_info_dict should hold ' 'only 4 * N numbers.') groundtruth_rects = convert_to_rectangle_list(groundtruth_coordinates) rects = convert_to_rectangle_list(coordinates) matching = Matching(groundtruth_rects, rects) image_statistics_list = [] groundtruth_rects_matched, rects_matched = ( matching.matching_by_greedy_assignment(iou_threshold)) image_statistics = compute_statistics_given_rectangle_matches( groundtruth_rects_matched, rects_matched) image_statistics_list.append(image_statistics) # Compute the precision and recall under this iou_threshold. precision_recall = compute_precision_recall_given_image_statistics_list( iou_threshold, image_statistics_list) # Compute the average_precision and average_recall. #average_precision, average_recall = ( # compute_average_precision_recall_given_precision_recall_dict( # precision_recall_dict)) return precision_recall
def test_getitem(): """ Check that you can access items in a Matching correctly. """ matching = Matching(dictionary) for key, val in matching.items(): assert matching[key] == val
class Main(object): """main loop of the game""" def __init__(self): pygame.init() # 包括读取设置文件,设置游戏基本属性 self.initAttr() # 传递所需的参数,实例化所包含的各个类 self.initObj() self.initContext() def initAttr(self): self.width, self.height = WINDOW_WIDTH, WINDOW_HEIGHT self.state = STATE.menu self.running = True self.level = SETLEVEL["DEFAULT_LEVEL"] self.channelID = None def initObj(self): # 设置大小,用于背景图片的缩放 self.gameNet = GameNet(self) self.gameNet.connectToServer() self.menu = Menu((self.width, self.height), self) self.rules = Rules(self.width, self.height) self.setLevel = SetLevel(self.width, self.height) self.matching = Matching((self.width, self.height), self) self.game = Game(self) # finish 界面的大小和游戏界面一样 self.finish = Finish((self.game.width, self.game.height)) # 绘制游戏主窗体 def initContext(self): self.screen = pygame.display.set_mode((self.width, self.height), DOUBLEBUF) pygame.display.set_caption("Boxes") self.clock = pygame.time.Clock(); def linkSuccess(self): print "link success" print self.channelID def enterMatching(self): self.matching.getRooms() def enemyComming(self, turn, gameID): self.gameID = gameID self.game.enemyComming(turn) self.game.setHome() def joinGame(self, level, gameID, turn): self.game = Game(self) self.game.gameID = gameID self.state = STATE.game self.game.setLevel(level) self.game.enemyComming(turn) self.game.setAway() def enterMenu(self): self.state = STATE.menu # 进入游戏界面事件 def enterGame(self, level): self.game.setLevel(level) self.game.initContext() self.state = STATE.game def startedNewGame(self, level): print "open room", level self.gameNet.openRoom(level) def leaveServer(self, gameID): self.gameNet.leaveServer(self.gameID) self.state = STATE.menu def backToMenu(self): self.initContext() self.state = STATE.menu def addScore(self): self.game.addScore() def enemyAddScore(self): self.game.enemyAddScore() def getRooms(self, matching, page, num): self.gameNet.getRooms(matching, page, num) def update(self): self.clock.tick(60) self.screen.fill(0) self.gameNet.pump() if STATE.exit == self.state: exit() elif STATE.setLevel == self.state: var = self.setLevel.draw(self.screen) if (var in STATE): self.state = var else: self.startedNewGame(var) self.enterGame(var) elif STATE.game == self.state: self.state = self.game.draw() if (self.state != STATE.game): self.initContext() elif STATE.matching == self.state: self.state = self.matching.draw(self.screen) elif STATE.menu == self.state: self.menu.draw(self.screen) self.state = self.menu.clickListener() elif STATE.rules == self.state: self.rules.draw(self.screen) self.state = self.rules.clickListener() elif STATE.finish == self.state: var = self.finish.draw(self.screen) if (var != STATE.finish): self.backToMenu() for event in pygame.event.get(): if (event.type == pygame.QUIT): if STATE.game == self.state: self.gameNet.exitFlag = True self.gameNet.leaveServer(self.game.gameID) sleep(0.5) pygame.quit() exit() else: pygame.quit() exit() # exit() # if (event.type == pygame.KEYDOWN): # if (event.key == pygame.K_ESCAPE): # exit() # pygame.quit() pygame.display.flip() def winning(self): self.finish.setWin(self.game.gameID) self.enterFinish() def lost(self): self.finish.setLost(self.game.gameID) self.enterFinish() def drawGame(self): self.finish.setDraw(self.game.gameID) self.enterFinish() def enterFinish(self): self.state = STATE.finish def run(self): while self.running: self.update() def exit(self): pygame.quit() exit()