def astar(stare_initiala, stare_finala, euristica, lista_chei): nod_initial = Nod(stare_initiala, None, None) deschise = SortedSet([nod_initial]) scor_optim = SortedDict({tuple(stare_initiala): 0}) # [1, 1, 1, 1, 1] # (1, 1, 1, 1, 1) while len(deschise) > 0: # extragem nodul cu f minim nod = deschise[0] deschise.pop(0) # daca am ajuns la starea finala, ne oprim if nod.stare == stare_finala: return nod # generam succesorii si facem verificari lista_succesori = genereaza_succesori(nod, lista_chei, euristica) for succesor in lista_succesori: if scor_optim.__contains__(tuple(succesor.stare)) == False: # daca starea succesorului nu a mai fost intalnita pana acum, o inseram scor_optim[tuple(succesor.stare)] = succesor.g deschise.add(succesor) elif succesor.g < scor_optim[tuple(succesor.stare)]: # introducem/editam starea curenta in setul "deschis", dupa caz succesor_fals = Nod(succesor.stare, None, None) succesor_fals.f = scor_optim[tuple( succesor.stare)] + euristica(succesor.stare) if deschise.__contains__(succesor_fals) is True: deschise.discard(succesor) deschise.add(succesor) # daca starea curenta este intalnita cu un cost mai mic, o reactualizam scor_optim[tuple(succesor.stare)] = succesor.g return None
class LeafSet(object): __slots__ = ('peers', 'capacity') __passthru = {'get', 'clear', 'pop', 'popitem', 'peekitem', 'key'} __iters = {'keys', 'values', 'items'} def __init__(self, my_key, iterable=(), capacity=8): try: iterable = iterable.items() # view object except AttributeError: pass tuple_itemgetter = Peer.distance(my_key, itemgetter(0)) key_itemgetter = Peer.distance(my_key) self.capacity = capacity self.peers = SortedDict(key_itemgetter) if iterable: l = sorted(iterable, key=tuple_itemgetter) self.peers.update(islice(l, capacity)) def clear(self): self.peers.clear() def prune(self): extra = len(self) - self.capacity for i in range(extra): self.peers.popitem(last=True) def update(self, iterable): try: iterable = iterable.items() # view object except AttributeError: pass iterable = iter(iterable) items = tuple(islice(iterable, 500)) while items: self.peers.update(items) items = tuple(islice(iterable, 500)) def setdefault(self, *args, **kwargs): self.peers.setdefault(*args, **kwargs) self.prune() def __setitem__(self, *args, **kwargs): self.peers.__setitem__(*args, **kwargs) self.prune() def __getitem__(self, *args, **kwargs): return self.peers.__getitem__(*args, **kwargs) def __delitem__(self, *args, **kwargs): return self.peers.__delitem__(*args, **kwargs) def __iter__(self, *args, **kwargs): return self.peers.__iter__(*args, **kwargs) def __reversed__(self, *args, **kwargs): return self.peers.__reversed__(*args, **kwargs) def __contains__(self, *args, **kwargs): return self.peers.__contains__(*args, **kwargs) def __len__(self, *args, **kwargs): return self.peers.__len__(*args, **kwargs) def __getattr__(self, key): if key in self.__class__.__passthru: return getattr(self.peers, key) elif key in self.__class__.__iters: return getattr(self.peers, 'iter' + key) else: return super().__getattr__(key) def __repr__(self): return '<%s keys=%r capacity=%d/%d>' % ( self.__class__.__name__, list(self), len(self), self.capacity)
class MemberList: def __init__(self, manager): self.manager = manager self.member_map = {} self.name_map = SortedDict() self.phone_map = SortedDict() self.email_map = SortedDict() self.yob_map = SortedDict() self.id = 1 def add_member(self, name, phone, email, yob): # if Member.name not in self.name_map: # self.name_map[Member.name] = [] # self.name_map[Member.name].append(self.id) self.member_map[self.id] = Member(name, phone, email, yob) if not self.name_map.__contains__(name): self.name_map[name] = [] self.name_map[name].append(self.id) if not self.phone_map.__contains__(phone): self.phone_map[phone] = [] self.phone_map[phone].append(self.id) if not self.email_map.__contains__(email): self.email_map[email] = [] self.email_map[email].append(self.id) if not self.yob_map.__contains__(yob): self.yob_map[yob] = [] self.yob_map[yob].append(self.id) self.id += 1 #ger herna lika undo_operation def add_sport_to_member(self, member, sport): member.sports.append(sport) def find_member_by_name(self, member): for name, id in self.name_map.items(): if name == member: return self.member_map[id[0]] return False def remove_member(self, name): if name in self.name_map: member_id = self.name_map[name][0] member = self.member_map[member_id] del self.name_map[member.name][0] if not self.name_map[member.name]: del self.name_map[member.name] del self.member_map[member_id] del self.phone_map[member.phone][0] if not self.phone_map[member.phone]: del self.phone_map[member.phone] del self.yob_map[member.yob][0] if not self.yob_map[member.yob]: del self.yob_map[member.yob] del self.email_map[member.email][0] if not self.email_map[member.email]: del self.email_map[member.email] return True return False #geri svo herna undo_operation def get_members_ordered_by_name(self): ordered_list = [] for _, value in self.name_map.items(): for i in value: ordered_list.append(self.member_map[int(i)]) return ordered_list def get_members_ordered_by_age(self): ordered_list = [] for _, value in self.yob_map.items(): for i in value: ordered_list.append(self.member_map[int(i)]) return ordered_list def retrieve_by_name(self, member_name): member_list = [] for member, member_id in self.name_map.items(): if member == member_name: for i in member_id: member_list.append(self.member_map[int(i)]) return member_list def retrieve_by_phone(self, phone_nr): member_list = [] for phone, phone_user_id in self.phone_map.items(): if phone == phone_nr: for i in phone_user_id: member_list.append(self.member_map[int(i)]) return member_list def retrieve_by_yob(self, yob_nr): member_list = [] for yob, yob_id in self.yob_map.items(): if yob == yob_nr: for i in yob_id: member_list.append(self.member_map[int(i)]) return member_list def retrieve_by_email(self, email_nr): member_list = [] for email, email_id in self.email_map.items(): if email == email_nr: for i in email_id: member_list.append(self.member_map[int(i)]) return member_list
class Learner(Mozillian): def __init__(self, row): super().__init__(row) self.submitted_dt = row['Timestamp'] self.time_availability_to_set(row['Time Availability']) self.interests_to_set(row['Interested in improving']) # if missing change_track value, set to unbias value of 3 self.change_track = safe_cast(row['Interest in changing career track'], int, 3) assert self.change_track in [ 1, 2, 3, 4, 5 ], self.get_id() + " has invalid change_track value " + str( self.change_track) # if missing outside_org value, set to unbias value of 2 self.outside_org = safe_cast( row['Interest in mentoring or learning from someone outside your own organization?'], int, 2) assert self.outside_org in [ 1, 2, 3 ], self.get_id() + " has invalid outside_org value " + str( self.outside_org) self.requests = row['Any particular requests?'] self.identify_as = row['Do you identify yourself as'] self.welcome_email_dt = row['Sent Wecome Email (date)'] self.notify_manager_dt = row['Sent Manager Approval Email (date)'] self.manager_approved_dt = row['Manager Approved (date)'] #self.preferences = SortedDict(neg) #, enumerate('abc', start=1)) #self.mentor_score = {} def time_availability_to_set(self, availability): """ Set times person is available in set form """ self.availability_set = set( [x.strip() for x in availability.split(',')]) #print(self.availability_set) def interests_to_set(self, interests): """ Set person's interest(s) in set form """ self.interests_set = set([x.strip() for x in interests.split(',')]) #print(self.interests_set) def get_submitted_dt(self) -> datetime: return self.submitted_dt def get_interests(self) -> set: return self.interests_set def get_times_available(self) -> set: return self.availability_set def get_outside_org_score(self, mentor) -> int: # outside org 1=prefer, 3=rather not assert mentor.org is not None, "Mentor " + mentor.get_id( ) + " has invalid org value " + mentor.track if self.outside_org == 1: if self.org == mentor.org: return 1 else: return 3 elif self.outside_org == 2: if self.org == mentor.org: return 2 else: return 2 elif self.outside_org == 3: if self.org == mentor.org: return 3 else: return 1 def get_change_track_score(self, mentor) -> int: # change career track 1=not interested, 5=very interested => give pref to mentors outside assert mentor.track is not None, "Mentor " + mentor.get_id( ) + " has invalid track value " + mentor.track if self.change_track == 1: if self.track != mentor.track: return 1 else: return 5 if self.change_track == 2: if self.track != mentor.track: return 2 else: return 4 if self.change_track == 3: if self.track != mentor.track: return 3 else: return 3 if self.change_track == 4: if self.track != mentor.track: return 4 else: return 1 if self.change_track == 5: if self.track != mentor.track: return 5 else: return 1 def calc_score(self, mentor, is_requested): # get count of overlapping times available_times = len( self.availability_set.intersection(mentor.get_times_available())) # If constraints are satisfied, calculate preference rankings for learners based on feature vector score = 0 # add bias for requested mentor if is_requested: score = score + 50 if available_times > 0: # match expertise to interest, max score of 7 # need to account for "Other:" somehow score = score + len( self.interests_set.intersection(mentor.get_expertise())) score = score + self.get_outside_org_score(mentor) score = score + self.get_change_track_score(mentor) return score def set_preferences(self, mentors: dict, requested_mentor=""): self.preferences = SortedDict(neg) #, enumerate('abc', start=1)) self.mentor_score = {} for mentor_id, mentor in mentors.items(): # Filter on constraints # cannot match to themselves if self.get_id() == mentor_id: continue # mentor-learner should not be in the same management reporting chain - will need ppl dataset info # for now just check that learner's manager = mentor or mentor's manager = learner if self.get_manager_email( ) == mentor_id or mentor.get_manager_email() == self.get_id(): continue # unless manager says "no", manager approved column has no impact # get count of overlapping times available_times = len( self.availability_set.intersection( mentor.get_times_available())) # If constraints are satisfied, calculate preference rankings for mentors based on feature vector score = 0 # add bias for requested mentor if mentor_id == requested_mentor: score = score + 50 if available_times > 0: # attribute, rank, weight # score will be learner's sum of weighted attributes # match interests to expertise, max score of 7 # need to account for "Other:" somehow score = score + len( self.interests_set.intersection(mentor.get_expertise())) #print("interests intersection score:" + str(score)) score = score + self.get_outside_org_score(mentor) score = score + self.get_change_track_score(mentor) # so far learner ranks range is [2,18] # be careful matching those in relationship/married/dating/familial - How?? # option to constrain mentor org level > learner org level? do levels translate across M/P? # if score is the same, order by date_submitted? no i think this is used in the apposite & global draw #print(mentor.get_id() + ": " + str(score)) if score > 0: if self.preferences.__contains__(score): self.preferences[score].append(mentor) else: self.preferences[score] = [mentor] #data_dict[regNumber].append(details) if self.preferences.__contains__(score) else self.preferences.update({score : [mentor]}) self.mentor_score[mentor_id] = score def get_preferences(self) -> SortedDict: return self.preferences def get_ranked_mentors(self) -> list: ranked_mentors = [] # add weights to those scores that are the same? for value in self.preferences.values(): ranked_mentors.extend([x.get_id() for x in value]) return ranked_mentors def get_mentor_score(self) -> dict: return self.mentor_score def get_mentor_rank(self, mentor, is_requested) -> int: #scores = [score for subscribed_learner_id, score in self.learner_score.items() if subscribed_learner_id == learner.get_id()] return self.calc_score(mentor, is_requested)
class DotMap(MutableMapping): def __init__(self, *args, **kwargs): self._map = SortedDict() if args: d = args[0] if type(d) is dict: for k, v in self.__call_items(d): if type(v) is dict: v = DotMap(v) self._map[k] = v if kwargs: for k, v in self.__call_items(kwargs): self._map[k] = v @staticmethod def __call_items(obj): if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')): return obj.iteritems() else: return obj.items() def items(self): return self.iteritems() def iteritems(self): return self.__call_items(self._map) def __iter__(self): return self._map.__iter__() def __setitem__(self, k, v): self._map[k] = v def __getitem__(self, k): if k not in self._map: # automatically extend to new DotMap self[k] = DotMap() return self._map[k] def __setattr__(self, k, v): if k == '_map': super(DotMap, self).__setattr__(k, v) else: self[k] = v def __getattr__(self, k): if k == '_map': return self._map else: return self[k] def __delattr__(self, key): return self._map.__delitem__(key) def __contains__(self, k): return self._map.__contains__(k) def __str__(self): items = [] for k, v in self.__call_items(self._map): items.append('{0}={1}'.format(k, repr(v))) out = 'DotMap({0})'.format(', '.join(items)) return out def __repr__(self): return str(self) def to_dict(self): d = {} for k, v in self.items(): if type(v) is DotMap: v = v.to_dict() d[k] = v return d def pprint(self): pprint(self.to_dict()) # proper dict subclassing def values(self): return self._map.values() @staticmethod def parse_other(other): if type(other) is DotMap: return other._map else: return other def __cmp__(self, other): other = DotMap.parse_other(other) return self._map.__cmp__(other) def __eq__(self, other): other = DotMap.parse_other(other) if not isinstance(other, dict): return False return self._map.__eq__(other) def __ge__(self, other): other = DotMap.parse_other(other) return self._map.__ge__(other) def __gt__(self, other): other = DotMap.parse_other(other) return self._map.__gt__(other) def __le__(self, other): other = DotMap.parseOther(other) return self._map.__le__(other) def __lt__(self, other): other = DotMap.parse_other(other) return self._map.__lt__(other) def __ne__(self, other): other = DotMap.parse_other(other) return self._map.__ne__(other) def __delitem__(self, key): return self._map.__delitem__(key) def __len__(self): return self._map.__len__() def copy(self): return self def get(self, key, default=None): return self._map.get(key, default) def has_key(self, key): return key in self._map def iterkeys(self): return self._map.iterkeys() def itervalues(self): return self._map.itervalues() def keys(self): return self._map.keys() def pop(self, key, default=None): return self._map.pop(key, default) def setdefault(self, key, default=None): return self._map.setdefault(key, default) def viewitems(self): if version_info.major == 2 and version_info.minor >= 7: return self._map.viewitems() else: return self._map.items() def viewkeys(self): if version_info.major == 2 and version_info.minor >= 7: return self._map.viewkeys() else: return self._map.keys() def viewvalues(self): if version_info.major == 2 and version_info.minor >= 7: return self._map.viewvalues() else: return self._map.values() @classmethod def fromkeys(cls, seq, value=None): d = DotMap() d._map = SortedDict.fromkeys(seq, value) return d
class Mentor(Mozillian): def __init__(self, row): super().__init__( row ) #row['Email Address'], row['Organizational level (i.e. P3, M2, etc.)'], row['Organization'], row['Participant full name'], row['Manager email']) self.submitted_dt = row['Timestamp'] self.time_availability_to_set(row['Time Availability']) self.expertise_to_set(row['Areas of expertise']) # if missing outside_org value, set to unbias value of 2 self.outside_org = safe_cast( row['Interest in mentoring or learning from someone outside your own organization?'], int, 2) assert self.outside_org in [ 1, 2, 3 ], self.get_id() + " has invalid outside_org value " + str( self.outside_org) self.requests = row['Any particular requests?'] self.identify_as = row['Do you identify yourself as'] self.welcome_email_dt = row['Sent Wecome Email (date)'] self.notify_manager_dt = row['Sent Manager Approval Email (date)'] self.manager_approved_dt = row['Manager Approved (date)'] self.mentee_limit = safe_cast( row['Mentee Limit'], int, 2) # by default mentors have a max of two mentees def time_availability_to_set(self, availability): """ Set times person is available in set form """ self.availability_set = set( [x.strip() for x in availability.split(',')]) def expertise_to_set(self, expertise): """ Set person's expertise in set form """ self.expertise_set = set([x.strip() for x in expertise.split(',')]) def get_submitted_dt(self) -> datetime: return self.submitted_dt def get_expertise(self) -> set: return self.expertise_set def get_times_available(self) -> set: return self.availability_set def get_mentee_limit(self) -> int: return self.mentee_limit def set_mentee_limit(self, mentee_limit: int): self.mentee_limit = mentee_limit def get_outside_org_score(self, learner) -> int: # outside org 1=prefer, 3=rather not assert learner.org is not None, "Learner " + learner.get_id( ) + " has invalid org value " + learner.track if self.outside_org == 1: if self.org == learner.org: return 1 else: return 3 elif self.outside_org == 2: if self.org == learner.org: return 2 else: return 2 elif self.outside_org == 3: if self.org == learner.org: return 3 else: return 1 def calc_score(self, learner, is_requested): # get count of overlapping times available_times = len( self.availability_set.intersection(learner.get_times_available())) # If constraints are satisfied, calculate preference rankings for learners based on feature vector score = 0 # add bias for requested mentor if is_requested: score = score + 50 if available_times > 0: # match expertise to interest, max score of 7 # need to account for "Other:" somehow score = score + len( self.expertise_set.intersection(learner.get_interests())) score = score + self.get_outside_org_score(learner) return score def set_preferences(self, learners): self.preferences = SortedDict(neg) #, enumerate('abc', start=1)) for learner in learners: # Filter on constraints # cannot match to themselves if self.get_id() == learner.get_id(): continue # mentor-learner should not be in the same management reporting chain - will need ppl dataset info # for now just check that learner's manager = mentor if self.get_manager_email() == learner.get_id(): continue # unless manager says "no", manager approved column has no impact # get count of overlapping times available_times = len( self.availability_set.intersection( learner.get_times_available())) # If constraints are satisfied, calculate preference rankings for learners based on feature vector score = 0 if available_times > 0: # match expertise to interest, max score of 7 # need to account for "Other:" somehow score = score + len( self.expertise_set.intersection(learner.get_interests())) #print("interests intersection score:" + str(score)) # outside org 1=prefer, 3=rather not # add 1 if prefer and orgs not the same if self.outside_org == 1 and self.org != learner.org: #print("outside org add 1: " + mentor_org) score = score + 1 # add 1 if rather not and orgs are the same if self.outside_org == 3 and self.org == learner.org: #print("outside org add 1: " + mentor_org) score = score + 1 # so far ranks range is [0,8] # be careful matching those in relationship/married/dating/familial - How?? # option to constrain mentor org level > learner org level? # if score is the same, order by date_submitted? no i think this is used in the apposite & global draw #print(mentor.get_id() + ": " + str(score)) if score > 0: if self.preferences.__contains__(score): self.preferences[score].append(learner) else: self.preferences[score] = [learner] def set_preferences_subscribed(self, subscribed_learners: dict, requested_learner=""): self.preferences = SortedDict(neg) #, enumerate('abc', start=1)) self.learner_score = {} for subscribed_learner_id, subscribed_learner in subscribed_learners.items( ): # Filter on constraints # cannot match to themselves if self.get_id() == subscribed_learner_id: continue # mentor-learner should not be in the same management reporting chain - will need ppl dataset info # for now just check that learner's manager = mentor if self.get_manager_email( ) == subscribed_learner_id or subscribed_learner.get_manager_email( ) == self.get_id(): continue # unless manager says "no", manager approved column has no impact # get count of overlapping times available_times = len( self.availability_set.intersection( subscribed_learner.get_times_available())) # If constraints are satisfied, calculate preference rankings for learners based on feature vector score = 0 # add bias for requested mentor if subscribed_learner_id == requested_learner: print(self.get_id() + ' requested learner: ' + requested_learner) score = score + 50 if available_times > 0: # match expertise to interest, max score of 7 # need to account for "Other:" somehow score = score + len( self.expertise_set.intersection( subscribed_learner.get_interests())) #print("interests intersection score:" + str(score)) score = score + self.get_outside_org_score(subscribed_learner) # so far ranks range is [2,13] # be careful matching those in relationship/married/dating/familial - How?? # option to constrain mentor org level > learner org level? do levels translate across M/P? # if score is the same, order by date_submitted? no i think this is used in the apposite & global draw #print(mentor.get_id() + ": " + str(score)) #if score > 0: if self.preferences.__contains__(score): self.preferences[score].append(subscribed_learner) else: self.preferences[score] = [subscribed_learner] self.learner_score[subscribed_learner_id] = score def get_preferences(self) -> SortedDict: return self.preferences def get_ranked_learners(self) -> list: ranked_learners = [] # add weights to those scores that are the same? for value in self.preferences.values(): ranked_learners.extend([x.get_id() for x in value]) #for score, learners_list in self.preferences.items(): # print("score: " + str(score) + ", learners: " + ','.join([x.get_id() for x in learners_list])) return ranked_learners def get_learner_score(self) -> dict: return self.learner_score def get_learner_rank(self, learner, is_requested) -> int: #scores = [score for subscribed_learner_id, score in self.learner_score.items() if subscribed_learner_id == learner.get_id()] return self.calc_score(learner, is_requested)