예제 #1
0
def generate_binary_performance_table_and_assignments(criteria,
                                                      categories, fmins):
    cids = list(criteria.keys())
    cats = categories.get_ordered_categories()
    aa = AlternativesAssignments()
    pt = PerformanceTable()
    i = 1
    for coalition in powerset(cids):
        if set(coalition) == set({}) or set(coalition) == set(cids):
            continue

        aid = "a%d" % i
        ap = AlternativePerformances(aid,
                                     OrderedDict({c: 1 if c in coalition else 0
                                                  for c in cids}))
        pt.append(ap)

        cat = cats[0]
        for fmin in fmins:
            if fmin.issubset(set(coalition)) is True:
                cat = cats[1]
                break

        aa.append(AlternativeAssignment(aid, cat))

        i += 1

    return pt, aa
예제 #2
0
def generate_binary_performance_table_and_assignments(criteria, categories,
                                                      fmins):
    cids = list(criteria.keys())
    cats = categories.get_ordered_categories()
    aa = AlternativesAssignments()
    pt = PerformanceTable()
    i = 1
    for coalition in powerset(cids):
        if set(coalition) == set({}) or set(coalition) == set(cids):
            continue

        aid = "a%d" % i
        ap = AlternativePerformances(
            aid, OrderedDict({c: 1 if c in coalition else 0
                              for c in cids}))
        pt.append(ap)

        cat = cats[0]
        for fmin in fmins:
            if fmin.issubset(set(coalition)) is True:
                cat = cats[1]
                break

        aa.append(AlternativeAssignment(aid, cat))

        i += 1

    return pt, aa
예제 #3
0
def compute_assignments_majority(models_ca, pt):
    models =  sorted(models_ca, key = lambda k: models_ca[k],
                      reverse = True)

    models_aa = {}
    for model in models[:len(models)/2]:
        models_aa[model] = model.get_assignments(pt)

    aa = AlternativesAssignments()
    for ap in pt:
        aid = ap.id
        cat_scores = {}
        for model in models[:int(math.ceil(len(models) / 2))]:
            cat = models_aa[model][aid].category_id
            if cat in cat_scores:
                cat_scores[cat] += models_ca[model]
            else:
                cat_scores[cat] = models_ca[model]

        b = AlternativeAssignment(aid,
                                  max(cat_scores,
                                      key = lambda cat: cat_scores[cat]))
        aa.append(b)

    return aa
예제 #4
0
파일: utils.py 프로젝트: oso/pymcda
def discard_alternatives_in_category(aa, category):
    out = AlternativesAssignments()

    for a in aa:
        if a.category_id != category:
            out.append(a)

    return out
예제 #5
0
def discard_alternatives_in_category(aa, category):
    out = AlternativesAssignments()

    for a in aa:
        if a.category_id != category:
            out.append(a)

    return out
예제 #6
0
def discard_undersorted_alternatives(categories, aa, aa2):
    out = AlternativesAssignments()
    cat_order = {cat: i + 1 for i, cat in enumerate(categories)}
    for a in aa:
        aid = a.id
        acat = cat_order[a.category_id]
        a2 = aa2[aid]
        a2cat = cat_order[a2.category_id]
        if a2cat >= acat:
            out.append(a)

    return out
예제 #7
0
파일: utils.py 프로젝트: oso/pymcda
def discard_undersorted_alternatives(categories, aa, aa2):
    out = AlternativesAssignments()
    cat_order = {cat: i + 1 for i, cat in enumerate(categories)}
    for a in aa:
        aid = a.id
        acat = cat_order[a.category_id]
        a2 = aa2[aid]
        a2cat = cat_order[a2.category_id]
        if a2cat >= acat:
            out.append(a)

    return out
예제 #8
0
파일: utils.py 프로젝트: oso/pymcda
def add_errors_in_assignments(aa, category_ids, errors_pc):
    n = int(len(aa)*errors_pc)
    aa_erroned = random.sample(list(aa), n)

    l = AlternativesAssignments([])
    for a in aa_erroned:
        cat = a.category_id
        new_cat = a.category_id
        while new_cat == cat:
            new_cat = random.sample(category_ids, 1)[0]
        a.category_id = new_cat
        l.append(a)

    return l
예제 #9
0
def add_errors_in_assignments(aa, category_ids, errors_pc):
    n = int(len(aa) * errors_pc)
    aa_erroned = random.sample(list(aa), n)

    l = AlternativesAssignments([])
    for a in aa_erroned:
        cat = a.category_id
        new_cat = a.category_id
        while new_cat == cat:
            new_cat = random.sample(category_ids, 1)[0]
        a.category_id = new_cat
        l.append(a)

    return l
예제 #10
0
def add_errors_in_assignments_proba(aa, category_ids, proba):
    l = AlternativesAssignments([])

    for a in aa:
        r = random.random()
        if r <= proba:
            cat = a.category_id
            new_cat = a.category_id
            while new_cat == cat:
                new_cat = random.sample(category_ids, 1)[0]
            a.category_id = new_cat

            l.append(a)

    return l
예제 #11
0
파일: utils.py 프로젝트: oso/pymcda
def add_errors_in_assignments_proba(aa, category_ids, proba):
    l = AlternativesAssignments([])

    for a in aa:
        r = random.random()
        if r <= proba:
            cat = a.category_id
            new_cat = a.category_id
            while new_cat == cat:
                new_cat = random.sample(category_ids, 1)[0]
            a.category_id = new_cat

            l.append(a)

    return l
예제 #12
0
    def optimist(self, pt):
        self.__check_input_params()
        profiles = self.profiles
        assignments = AlternativesAssignments([])
        for action_perfs in pt:
            cat_rank = 0
            for i, profile in enumerate(profiles):
                outr = self.__outrank(action_perfs, self.criteria,
                                      self.bpt[profile], self.lbda)
                if outr != "-":
                    cat_rank += 1

            cat_id = self.categories[cat_rank]
            id = action_perfs.id
            alt_affect = AlternativeAssignment(id, cat_id)
            assignments.append(alt_affect)

        return assignments
예제 #13
0
파일: electre_tri.py 프로젝트: oso/pymcda
    def optimist(self, pt):
        self.__check_input_params()
        profiles = self.profiles
        assignments = AlternativesAssignments([])
        for action_perfs in pt:
            cat_rank = 0
            for i, profile in enumerate(profiles):
                outr = self.__outrank(action_perfs, self.criteria,
                                      self.bpt[profile], self.lbda)
                if outr != "-":
                    cat_rank += 1

            cat_id = self.categories[cat_rank]
            id = action_perfs.id
            alt_affect = AlternativeAssignment(id, cat_id)
            assignments.append(alt_affect)

        return assignments
예제 #14
0
파일: electre_tri.py 프로젝트: oso/pymcda
    def pessimist(self, pt):
        self.__check_input_params()
        profiles = self.profiles[:]
        profiles.reverse()
        assignments = AlternativesAssignments([])
        for action_perfs in pt:
            cat_rank = len(profiles)
            for i, profile in enumerate(profiles):
                s_ab = self.credibility(action_perfs, self.bpt[profile],
                                        profile)
                if not eq(s_ab, self.lbda) and s_ab < self.lbda:
                    cat_rank -= 1

            cat_id = self.categories[cat_rank]
            id = action_perfs.id
            alt_affect = AlternativeAssignment(id, cat_id)
            assignments.append(alt_affect)

        return assignments
예제 #15
0
    def pessimist(self, pt):
        self.__check_input_params()
        profiles = self.profiles[:]
        profiles.reverse()
        assignments = AlternativesAssignments([])
        for action_perfs in pt:
            cat_rank = len(profiles)
            for i, profile in enumerate(profiles):
                s_ab = self.credibility(action_perfs, self.bpt[profile],
                                        profile)
                if not eq(s_ab, self.lbda) and s_ab < self.lbda:
                    cat_rank -= 1

            cat_id = self.categories[cat_rank]
            id = action_perfs.id
            alt_affect = AlternativeAssignment(id, cat_id)
            assignments.append(alt_affect)

        return assignments
def compute_assignments_majority(models_ca, pt):
    models = sorted(models_ca, key=lambda k: models_ca[k], reverse=True)

    models_aa = {}
    for model in models[:len(models) / 2]:
        models_aa[model] = model.get_assignments(pt)

    aa = AlternativesAssignments()
    for ap in pt:
        aid = ap.id
        cat_scores = {}
        for model in models[:int(math.ceil(len(models) / 2))]:
            cat = models_aa[model][aid].category_id
            if cat in cat_scores:
                cat_scores[cat] += models_ca[model]
            else:
                cat_scores[cat] = models_ca[model]

        b = AlternativeAssignment(
            aid, max(cat_scores, key=lambda cat: cat_scores[cat]))
        aa.append(b)

    return aa
class MetaMRSortProfiles3():
    def __init__(self, model, pt_sorted, aa_ori):
        self.na = len(aa_ori)
        self.model = model
        self.nprofiles = len(model.profiles)
        self.pt_sorted = pt_sorted
        self.aa_ori = aa_ori
        self.cat = self.categories_rank()
        self.cat_ranked = self.model.categories
        self.aa_by_cat = self.sort_alternative_by_category(aa_ori)
        self.b0 = pt_sorted.pt.get_worst(model.criteria)
        self.bp = pt_sorted.pt.get_best(model.criteria)
        self.compute_interval_ratios(3)
        self.build_concordance_table()
        self.build_assignments_table()

    def categories_rank(self):
        return {cat: i + 1 for i, cat in enumerate(self.model.categories)}

    def compute_interval_ratios(self, n):
        self.nintervals = n
        intervals = []
        for i in range(n - 1):
            intervals += [math.exp(i + 1)]
        s = sum(intervals)
        self.interval_ratios = [i / s for i in intervals] + [0.9]

    def update_intervals(self, fitness):
        if fitness > 0.99:
            self.compute_interval_ratios(8)
        elif fitness > 0.95:
            self.compute_interval_ratios(6)
        elif fitness > 0.9:
            self.compute_interval_ratios(5)
        else:
            self.compute_interval_ratios(4)

    def rank_categories(self, cat):
        c_rank = {c.id: c.rank for c in cat}
        return sorted([cat for cat in c_rank.iterkeys()])

    def sort_alternative_by_category(self, aa):
        aa_by_cat = {}
        for a in aa:
            aid = a.id
            cat = self.cat[a.category_id]
            if cat in aa_by_cat:
                aa_by_cat[cat].append(aid)
            else:
                aa_by_cat[cat] = [aid]
        return aa_by_cat

    def get_alternative_assignment(self, aid):
        profile = self.model.profiles[0]
        for profile in reversed(self.model.profiles):
            if self.ct[profile][aid] >= self.model.lbda:
                return self.model.categories_profiles[profile].value.upper

        return self.model.categories_profiles[profile].value.lower

    def build_assignments_table(self):
        self.good = 0
        self.aa = AlternativesAssignments()
        for aa in self.aa_ori.values():
            aid = aa.id
            cat = self.get_alternative_assignment(aid)
            self.aa.append(AlternativeAssignment(aid, cat))

            cat_ori = aa.category_id
            if cat == cat_ori:
                self.good += 1

    def build_concordance_table(self):
        self.ct = {bp.id: dict() for bp in self.model.bpt}
        for aid, bp in product(self.aa_ori.keys(), self.model.bpt):
            ap = self.pt_sorted[aid]
            conc = self.model.concordance(ap, bp)
            self.ct[bp.id][aid] = conc

    def rebuild_tables(self):
        self.build_concordance_table()
        self.build_assignments_table()

    def compute_above_histogram(self, cid, profile, above, cat_b, cat_a):
        h_above = {}
        size = above - profile
        intervals = [ profile + self.interval_ratios[i]*size \
                      for i in range(self.nintervals) ]
        intervals = [profile] + intervals
        ok = nok = 0
        for i in range(self.nintervals):
            alts = self.pt_sorted.get_middle(cid, intervals[i],
                                             intervals[i + 1])[0]
            for a in alts:
                if self.aa(a) == cat_b and self.aa_ori(a) == cat_a:
                    ok += 1
                elif self.aa(a) == cat_a:
                    if self.aa_ori(a) == cat_a:
                        ok += 1
                    elif self.aa_ori(a) == cat_b:
                        nok += 1

            if (ok + nok) > 0:
                h_above[intervals[i + 1]] = nok / (ok + nok)
            else:
                h_above[intervals[i + 1]] = 0

        return h_above

    def compute_below_histogram(self, cid, profile, below, cat_b, cat_a):
        h_below = {}
        size = profile - below
        intervals = [ profile - self.interval_ratios[i]*size \
                      for i in range(self.nintervals) ]
        intervals = [profile] + intervals
        ok = nok = 0
        for i in range(self.nintervals):
            alts = self.pt_sorted.get_middle(cid, intervals[i],
                                             intervals[i + 1])[0]
            for a in alts:
                if self.aa(a) == cat_a and self.aa_ori(a) == cat_b:
                    ok += 1
                elif self.aa(a) == cat_b:
                    if self.aa_ori(a) == cat_b:
                        ok += 1
                    elif self.aa_ori(a) == cat_a:
                        nok += 1

            if (ok + nok) > 0:
                h_below[intervals[i + 1]] = nok / (ok + nok)
            else:
                h_below[intervals[i + 1]] = 0

        return h_below

    def optimize_profile(self, profile, below, above, cat_b, cat_a):
        p_perfs = profile.performances
        a_perfs = above.performances
        b_perfs = below.performances

        moved = False
        max_val = 0

        for c in self.model.criteria:
            cid = c.id
            h_below = self.compute_below_histogram(cid, p_perfs[cid],
                                                   b_perfs[cid], cat_b, cat_a)
            h_above = self.compute_above_histogram(cid, p_perfs[cid],
                                                   a_perfs[cid], cat_b, cat_a)

            i_b = max(h_below, key=h_below.get)
            i_a = max(h_above, key=h_above.get)
            r = random.random()

            if h_below[i_b] > h_above[i_a]:
                if r < h_below[i_b]:
                    p_perfs[cid] = i_b
                    moved = True
                elif moved is False and h_below[i_b] > max_val:
                    max_val = h_below[i_b]
                    max_cid = cid
                    max_move = i_b
            elif h_below[i_b] < h_above[i_a]:
                if r < h_above[i_a]:
                    p_perfs[cid] = i_a
                    moved = True
                elif moved is False and h_above[i_a] > max_val:
                    max_val = h_above[i_a]
                    max_cid = cid
                    max_move = i_a
            elif r > 0.5:
                r2 = random.random()
                if r2 < h_below[i_b]:
                    p_perfs[cid] = i_b
                    moved = True
                elif moved is False and h_below[i_b] > max_val:
                    max_val = h_below[i_b]
                    max_cid = cid
                    max_move = i_b
            elif r < 0.5:
                r2 = random.random()
                if r2 < h_above[i_a]:
                    p_perfs[cid] = i_a
                    moved = True
                elif moved is False and h_above[i_a] > max_val:
                    max_val = h_above[i_a]
                    max_cid = cid
                    max_move = i_a

        if moved is False and max_val > 0:
            p_perfs[max_cid] = max_move

    def get_below_and_above_profiles(self, i):
        profiles = self.model.profiles
        bpt = self.model.bpt

        if i == 0:
            below = self.b0
        else:
            below = bpt[profiles[i - 1]]

        if i == self.nprofiles - 1:
            above = self.bp
        else:
            above = bpt[profiles[i + 1]]

        return below, above

    def optimize(self):
        profiles = self.model.profiles
        for i, profile in enumerate(profiles):
            pperfs = self.model.bpt[profile]
            below, above = self.get_below_and_above_profiles(i)
            cat_b, cat_a = self.cat_ranked[i], self.cat_ranked[i + 1]
            self.update_intervals(self.good / self.na)
            self.optimize_profile(pperfs, below, above, cat_b, cat_a)

        self.rebuild_tables()

        return self.good / self.na
예제 #18
0
    def get_assignments(self, pt):
        aas = AlternativesAssignments([])
        for ap in pt:
            aas.append(self.get_assignment(ap))

        return aas
예제 #19
0
 def get_assignments(self, pt):
     aa = AlternativesAssignments()
     for ap in pt:
         a = self.get_assignment(ap)
         aa.append(a)
     return aa
class MetaMRSortProfilesChoquet():
    def __init__(self, model, pt_sorted, aa_ori):
        self.na = len(aa_ori)
        self.nc = len(model.criteria)
        self.model = model
        self.nprofiles = len(model.profiles)
        self.pt_sorted = pt_sorted
        self.aa_ori = aa_ori
        self.cat = self.categories_rank()
        self.cat_ranked = self.model.categories
        self.aa_by_cat = self.sort_alternative_by_category(aa_ori)
        self.b0 = pt_sorted.pt.get_worst(model.criteria)
        self.bp = pt_sorted.pt.get_best(model.criteria)
        self.rebuild_tables()

    def categories_rank(self):
        return {cat: i + 1 for i, cat in enumerate(self.model.categories)}

    def sort_alternative_by_category(self, aa):
        aa_by_cat = {}
        for a in aa:
            aid = a.id
            cat = self.cat[a.category_id]
            if cat in aa_by_cat:
                aa_by_cat[cat].append(aid)
            else:
                aa_by_cat[cat] = [aid]
        return aa_by_cat

    def compute_above_histogram(self, cid, perf_profile, perf_above, cat_b,
                                cat_a, ct):
        lbda = self.model.lbda
        direction = self.model.criteria[cid].direction
        delta = 0.00001 * direction

        h_above = {}
        num = total = 0
        alts, perfs = self.pt_sorted.get_middle(cid, perf_profile, perf_above,
                                                True, True)

        for i, a in enumerate(alts):
            if (perfs[i] + delta) * direction > perf_above * direction:
                continue

            aa_ori = self.aa_ori._d[a].category_id
            aa = self.aa._d[a].category_id
            diff = self.mobius[frozenset(ct[a] | set([cid]))]
            if aa_ori == cat_a:
                if aa == cat_a and diff < lbda:
                    # --
                    total += 5
                elif aa == cat_b:
                    # -
                    total += 1
            elif aa_ori == cat_b and aa == cat_a:
                if diff >= lbda:
                    # +
                    num += 0.5
                    total += 1
                    h_above[perfs[i] + delta] = num / total
                else:
                    # ++
                    num += 2
                    total += 1
                    h_above[perfs[i] + delta] = num / total
#            elif self.aa_ori(a) < self.aa(a) and \
            elif aa_ori != aa and \
                 self.cat[aa] < self.cat[cat_a] and \
                 self.cat[aa_ori] < self.cat[cat_a]:
                num += 0.1
                total += 1
                h_above[perfs[i] + delta] = num / total

        return h_above

    def compute_below_histogram(self, cid, perf_profile, perf_below, cat_b,
                                cat_a, ct):
        lbda = self.model.lbda

        h_below = {}
        num = total = 0
        alts, perfs = self.pt_sorted.get_middle(cid, perf_profile, perf_below,
                                                True, True)

        for i, a in enumerate(alts):
            aa_ori = self.aa_ori._d[a].category_id
            aa = self.aa._d[a].category_id
            diff = self.mobius[frozenset(ct[a] | set([cid]))]
            if aa_ori == cat_a and aa == cat_b:
                if diff >= lbda:
                    # ++
                    num += 2
                    total += 1
                    h_below[perfs[i]] = num / total
                else:
                    # +
                    num += 0.5
                    total += 1
                    h_below[perfs[i]] = num / total
            elif aa_ori == cat_b:
                if aa == cat_b and diff >= lbda:
                    # --
                    total += 5
                elif aa == cat_a:
                    # -
                    total += 1


#            elif self.aa_ori(a) > self.aa(a) and \
            elif aa_ori != aa and \
                 self.cat[aa] > self.cat[cat_b] and \
                 self.cat[aa_ori] > self.cat[cat_b]:
                num += 0.1
                total += 1
                h_below[perfs[i]] = num / total

        return h_below

    def histogram_choose(self, h, current):
        key = random.choice(h.keys())
        val = h[key]
        diff = abs(current - key)
        for k, v in h.items():
            if v >= val:
                tmp = abs(current - k)
                if tmp > diff:
                    key = k
                    val = v
                    diff = tmp
        return key

    def get_alternative_assignment(self, aid):
        profile = self.model.profiles[0]
        for profile in reversed(self.model.profiles):
            if self.mobius[self.ct[profile][aid]] >= self.model.lbda:
                return self.model.categories_profiles[profile].value.upper

        return self.model.categories_profiles[profile].value.lower

    def build_assignments_table(self):
        self.good = 0
        self.aa = AlternativesAssignments()
        for aa in self.aa_ori.values():
            aid = aa.id
            cat = self.get_alternative_assignment(aid)
            self.aa.append(AlternativeAssignment(aid, cat))

            cat_ori = aa.category_id
            if cat == cat_ori:
                self.good += 1

    def build_concordance_table(self):
        self.ct = {bp.id: dict() for bp in self.model.bpt}
        for aid, bp in product(self.aa_ori.keys(), self.model.bpt):
            ap = self.pt_sorted[aid]
            conc = self.model.concordance(ap, bp)
            self.ct[bp.id][aid] = conc

    def build_coalition_table(self):
        self.ct = {bp.id: dict() for bp in self.model.bpt}
        for aid, bp in product(self.aa_ori.keys(), self.model.bpt):
            ap = self.pt_sorted[aid]
            criteria_coalition = self.model.criteria_coalition(ap, bp)
            self.ct[bp.id][aid] = frozenset(criteria_coalition)

    def build_mobius_table(self):
        cids = self.model.criteria.keys()
        self.mobius = {frozenset([]): 0}
        for i in range(len(cids)):
            for c in combinations(cids, i + 1):
                s = frozenset(c)
                wsum = self.model.coalition_weight(s)
                self.mobius[s] = wsum

    def rebuild_tables(self):
        self.build_mobius_table()
        self.build_coalition_table()
        self.build_assignments_table()

    def update_tables(self, profile, cid, old, new):
        direction = self.model.criteria[cid].direction
        if old > new:
            if direction == 1:
                down, up = True, False
            else:
                down, up = False, True
            add = True
        else:
            if direction == 1:
                down, up = False, True
            else:
                down, up = True, False
            add = False

        alts, perfs = self.pt_sorted.get_middle(cid, old, new, up, down)

        for a in alts:
            self.ct[profile][a] = set(self.ct[profile][a])
            if add is True:
                self.ct[profile][a].add(cid)
            else:
                self.ct[profile][a].discard(cid)
            self.ct[profile][a] = frozenset(self.ct[profile][a])

            old_cat = self.aa[a].category_id
            new_cat = self.get_alternative_assignment(a)
            ori_cat = self.aa_ori[a].category_id

            if old_cat == new_cat:
                continue
            elif old_cat == ori_cat:
                self.good -= 1
            elif new_cat == ori_cat:
                self.good += 1

            self.aa[a].category_id = new_cat

    def optimize_profile(self, profile, below, above, cat_b, cat_a):
        cids = self.model.criteria.keys()
        random.shuffle(cids)

        for cid in cids:
            ct = self.ct[profile.id]

            perf_profile = profile.performances[cid]
            perf_above = above.performances[cid]
            perf_below = below.performances[cid]

            h_below = self.compute_below_histogram(cid, perf_profile,
                                                   perf_below, cat_b, cat_a,
                                                   ct)
            h_above = self.compute_above_histogram(cid, perf_profile,
                                                   perf_above, cat_b, cat_a,
                                                   ct)
            h = h_below
            h.update(h_above)

            if not h:
                continue

            i = self.histogram_choose(h, perf_profile)

            r = random.uniform(0, 1)

            if r <= h[i]:
                self.update_tables(profile.id, cid, perf_profile, i)
                profile.performances[cid] = i

    def get_below_and_above_profiles(self, i):
        profiles = self.model.profiles
        bpt = self.model.bpt

        if i == 0:
            below = self.b0
        else:
            below = bpt[profiles[i - 1]]

        if i == self.nprofiles - 1:
            above = self.bp
        else:
            above = bpt[profiles[i + 1]]

        return below, above

    def optimize(self):
        profiles = self.model.profiles
        for i, profile in enumerate(profiles):
            pperfs = self.model.bpt[profile]
            below, above = self.get_below_and_above_profiles(i)
            cat_b, cat_a = self.cat_ranked[i], self.cat_ranked[i + 1]
            self.optimize_profile(pperfs, below, above, cat_b, cat_a)

        return self.good / self.na
예제 #21
0
class MetaMRSortProfiles3():

    def __init__(self, model, pt_sorted, aa_ori):
        self.na = len(aa_ori)
        self.model = model
        self.nprofiles = len(model.profiles)
        self.pt_sorted = pt_sorted
        self.aa_ori = aa_ori
        self.cat = self.categories_rank()
        self.cat_ranked = self.model.categories
        self.aa_by_cat = self.sort_alternative_by_category(aa_ori)
        self.b0 = pt_sorted.pt.get_worst(model.criteria)
        self.bp = pt_sorted.pt.get_best(model.criteria)
        self.compute_interval_ratios(3)
        self.build_concordance_table()
        self.build_assignments_table()

    def categories_rank(self):
        return { cat: i + 1 for i, cat in enumerate(self.model.categories) }

    def compute_interval_ratios(self, n):
        self.nintervals = n
        intervals = []
        for i in range(n-1):
            intervals += [ math.exp(i+1) ]
        s = sum(intervals)
        self.interval_ratios = [ i/s for i in intervals ] + [ 0.9 ]

    def update_intervals(self, fitness):
        if fitness > 0.99:
            self.compute_interval_ratios(8)
        elif fitness > 0.95:
            self.compute_interval_ratios(6)
        elif fitness > 0.9:
            self.compute_interval_ratios(5)
        else:
            self.compute_interval_ratios(4)

    def rank_categories(self, cat):
        c_rank = { c.id: c.rank for c in cat }
        return sorted([cat for cat  in c_rank.iterkeys()])

    def sort_alternative_by_category(self, aa):
        aa_by_cat = {}
        for a in aa:
            aid = a.id
            cat = self.cat[a.category_id]
            if cat in aa_by_cat:
                aa_by_cat[cat].append(aid)
            else:
                aa_by_cat[cat] = [ aid ]
        return aa_by_cat

    def get_alternative_assignment(self, aid):
        profile = self.model.profiles[0]
        for profile in reversed(self.model.profiles):
            if self.ct[profile][aid] >= self.model.lbda:
                return self.model.categories_profiles[profile].value.upper

        return self.model.categories_profiles[profile].value.lower

    def build_assignments_table(self):
        self.good = 0
        self.aa = AlternativesAssignments()
        for aa in self.aa_ori.values():
            aid = aa.id
            cat = self.get_alternative_assignment(aid)
            self.aa.append(AlternativeAssignment(aid, cat))

            cat_ori = aa.category_id
            if cat == cat_ori:
                self.good += 1

    def build_concordance_table(self):
        self.ct = { bp.id: dict() for bp in self.model.bpt }
        for aid, bp in product(self.aa_ori.keys(), self.model.bpt):
            ap = self.pt_sorted[aid]
            conc = self.model.concordance(ap, bp)
            self.ct[bp.id][aid] = conc

    def rebuild_tables(self):
        self.build_concordance_table()
        self.build_assignments_table()

    def compute_above_histogram(self, cid, profile, above, cat_b, cat_a):
        h_above = {}
        size = above - profile
        intervals = [ profile + self.interval_ratios[i]*size \
                      for i in range(self.nintervals) ]
        intervals = [ profile ] + intervals
        ok = nok = 0
        for i in range(self.nintervals):
            alts = self.pt_sorted.get_middle(cid, intervals[i],
                                             intervals[i+1])[0]
            for a in alts:
                if self.aa(a) == cat_b and self.aa_ori(a) == cat_a:
                    ok += 1
                elif self.aa(a) == cat_a:
                    if self.aa_ori(a) == cat_a:
                        ok += 1
                    elif self.aa_ori(a) == cat_b:
                        nok += 1

            if (ok + nok) > 0:
                h_above[intervals[i+1]] = nok / (ok + nok)
            else:
                h_above[intervals[i+1]] = 0

        return h_above

    def compute_below_histogram(self, cid, profile, below, cat_b, cat_a):
        h_below = {}
        size = profile - below
        intervals = [ profile - self.interval_ratios[i]*size \
                      for i in range(self.nintervals) ]
        intervals = [ profile ] + intervals
        ok = nok = 0
        for i in range(self.nintervals):
            alts = self.pt_sorted.get_middle(cid, intervals[i],
                                             intervals[i+1])[0]
            for a in alts:
                if self.aa(a) == cat_a and self.aa_ori(a) == cat_b:
                    ok += 1
                elif self.aa(a) == cat_b:
                    if self.aa_ori(a) == cat_b:
                        ok += 1
                    elif self.aa_ori(a) == cat_a:
                        nok += 1

            if (ok + nok) > 0:
                h_below[intervals[i+1]] = nok / (ok + nok)
            else:
                h_below[intervals[i+1]] = 0

        return h_below

    def optimize_profile(self, profile, below, above, cat_b, cat_a):
        p_perfs = profile.performances
        a_perfs = above.performances
        b_perfs = below.performances

        moved = False
        max_val = 0

        for c in self.model.criteria:
            cid = c.id
            h_below = self.compute_below_histogram(cid, p_perfs[cid],
                                                   b_perfs[cid], cat_b,
                                                   cat_a)
            h_above = self.compute_above_histogram(cid, p_perfs[cid],
                                                   a_perfs[cid], cat_b,
                                                   cat_a)

            i_b = max(h_below, key=h_below.get)
            i_a = max(h_above, key=h_above.get)
            r = random.random()

            if h_below[i_b] > h_above[i_a]:
                if r < h_below[i_b]:
                    p_perfs[cid] = i_b
                    moved = True
                elif moved is False and h_below[i_b] > max_val:
                    max_val = h_below[i_b]
                    max_cid = cid
                    max_move = i_b
            elif h_below[i_b] < h_above[i_a]:
                if r < h_above[i_a]:
                    p_perfs[cid] = i_a
                    moved = True
                elif moved is False and h_above[i_a] > max_val:
                    max_val = h_above[i_a]
                    max_cid = cid
                    max_move = i_a
            elif r > 0.5:
                r2 = random.random()
                if r2 < h_below[i_b]:
                    p_perfs[cid] = i_b
                    moved = True
                elif moved is False and h_below[i_b] > max_val:
                    max_val = h_below[i_b]
                    max_cid = cid
                    max_move = i_b
            elif r < 0.5:
                r2 = random.random()
                if r2 < h_above[i_a]:
                    p_perfs[cid] = i_a
                    moved = True
                elif moved is False and h_above[i_a] > max_val:
                    max_val = h_above[i_a]
                    max_cid = cid
                    max_move = i_a

        if moved is False and max_val > 0:
            p_perfs[max_cid] = max_move

    def get_below_and_above_profiles(self, i):
        profiles = self.model.profiles
        bpt = self.model.bpt

        if i == 0:
            below = self.b0
        else:
            below = bpt[profiles[i-1]]

        if i == self.nprofiles-1:
            above = self.bp
        else:
            above = bpt[profiles[i+1]]

        return below, above

    def optimize(self):
        profiles = self.model.profiles
        for i, profile in enumerate(profiles):
            pperfs = self.model.bpt[profile]
            below, above = self.get_below_and_above_profiles(i)
            cat_b, cat_a = self.cat_ranked[i], self.cat_ranked[i+1]
            self.update_intervals(self.good / self.na)
            self.optimize_profile(pperfs, below, above, cat_b, cat_a)

        self.rebuild_tables()

        return self.good / self.na
예제 #22
0
class MetaMRSortProfiles4():

    def __init__(self, model, pt_sorted, aa_ori):
        self.na = len(aa_ori)
        self.nc = len(model.criteria)
        self.model = model
        self.nprofiles = len(model.profiles)
        self.pt_sorted = pt_sorted
        self.aa_ori = aa_ori
        self.cat = self.categories_rank()
        self.cat_ranked = self.model.categories
        self.aa_by_cat = self.sort_alternative_by_category(aa_ori)
        self.b0 = pt_sorted.pt.get_worst(model.criteria)
        self.bp = pt_sorted.pt.get_best(model.criteria)
        self.build_concordance_table()
        self.build_assignments_table()

    def categories_rank(self):
        return { cat: i + 1 for i, cat in enumerate(self.model.categories) }

    def sort_alternative_by_category(self, aa):
        aa_by_cat = {}
        for a in aa:
            aid = a.id
            cat = self.cat[a.category_id]
            if cat in aa_by_cat:
                aa_by_cat[cat].append(aid)
            else:
                aa_by_cat[cat] = [ aid ]
        return aa_by_cat

    def compute_above_histogram(self, cid, perf_profile, perf_above,
                                cat_b, cat_a, ct):
        w = self.model.cv[cid].value
        lbda = self.model.lbda
        direction = self.model.criteria[cid].direction
        delta = 0.00001 * direction

        h_above = {}
        num = total = 0
        alts, perfs = self.pt_sorted.get_middle(cid,
                                                perf_profile, perf_above,
                                                True, True)

        for i, a in enumerate(alts):
            if (perfs[i] + delta) * direction > perf_above * direction:
                continue

            conc = ct[a]
            aa_ori = self.aa_ori._d[a].category_id
            aa = self.aa._d[a].category_id
            diff = conc - w
            if aa_ori == cat_a:
                if aa == cat_a and diff < lbda:
                    # --
                    total += 5
                elif aa == cat_b:
                    # -
                    total += 1
            elif aa_ori == cat_b and aa == cat_a:
                if diff >= lbda:
                    # +
                    num += 0.5
                    total += 1
                    h_above[perfs[i] + delta] = num / total
                else:
                    # ++
                    num += 2
                    total += 1
                    h_above[perfs[i] + delta] = num / total
#            elif self.aa_ori(a) < self.aa(a) and \
            elif aa_ori != aa and \
                 self.cat[aa] < self.cat[cat_a] and \
                 self.cat[aa_ori] < self.cat[cat_a]:
                num += 0.1
                total += 1
                h_above[perfs[i] + delta] = num / total

        return h_above

    def compute_below_histogram(self, cid, perf_profile, perf_below,
                                cat_b, cat_a, ct):
        w = self.model.cv[cid].value
        lbda = self.model.lbda

        h_below = {}
        num = total = 0
        alts, perfs = self.pt_sorted.get_middle(cid,
                                                perf_profile, perf_below,
                                                True, True)

        for i, a in enumerate(alts):
            conc = ct[a]
            aa_ori = self.aa_ori._d[a].category_id
            aa = self.aa._d[a].category_id
            diff = conc + w
            if aa_ori == cat_a and aa == cat_b:
                if diff >= lbda:
                    # ++
                    num += 2
                    total += 1
                    h_below[perfs[i]] = num / total
                else:
                    # +
                    num += 0.5
                    total += 1
                    h_below[perfs[i]] = num / total
            elif aa_ori == cat_b:
                if aa == cat_b and diff >= lbda:
                    # --
                    total += 5
                elif aa == cat_a:
                    # -
                    total += 1
#            elif self.aa_ori(a) > self.aa(a) and \
            elif aa_ori != aa and \
                 self.cat[aa] > self.cat[cat_b] and \
                 self.cat[aa_ori] > self.cat[cat_b]:
                num += 0.1
                total += 1
                h_below[perfs[i]] = num / total

        return h_below

    def histogram_choose(self, h, current):
        key = random.choice(h.keys())
        val = h[key]
        diff = abs(current - key)
        for k, v in h.items():
            if v >= val:
                tmp = abs(current - k)
                if tmp > diff:
                    key = k
                    val = v
                    diff = tmp
        return key

    def get_alternative_assignment(self, aid):
        profile = self.model.profiles[0]
        for profile in reversed(self.model.profiles):
            if self.ct[profile][aid] >= self.model.lbda \
               or eq(self.ct[profile][aid], self.model.lbda):
                return self.model.categories_profiles[profile].value.upper

        return self.model.categories_profiles[profile].value.lower

    def build_assignments_table(self):
        self.good = 0
        self.aa = AlternativesAssignments()
        for aa in self.aa_ori.values():
            aid = aa.id
            cat = self.get_alternative_assignment(aid)
            self.aa.append(AlternativeAssignment(aid, cat))

            cat_ori = aa.category_id
            if cat == cat_ori:
                self.good += 1

    def build_concordance_table(self):
        self.ct = { bp.id: dict() for bp in self.model.bpt }
        for aid, bp in product(self.aa_ori.keys(), self.model.bpt):
            ap = self.pt_sorted[aid]
            conc = self.model.concordance(ap, bp)
            self.ct[bp.id][aid] = conc

    def rebuild_tables(self):
        self.build_concordance_table()
        self.build_assignments_table()

    def update_tables(self, profile, cid, old, new):
        direction = self.model.criteria[cid].direction
        if old > new:
            if direction == 1:
                down, up = True, False
            else:
                down, up = False, True
            w = self.model.cv[cid].value * direction
        else:
            if direction == 1:
                down, up = False, True
            else:
                down, up = True, False
            w = -self.model.cv[cid].value * direction

        alts, perfs = self.pt_sorted.get_middle(cid, old, new, up, down)

        for a in alts:
            self.ct[profile][a] += w
            old_cat = self.aa[a].category_id
            new_cat = self.get_alternative_assignment(a)
            ori_cat = self.aa_ori[a].category_id

            if old_cat == new_cat:
                continue
            elif old_cat == ori_cat:
                self.good -= 1
            elif new_cat == ori_cat:
                self.good += 1

            self.aa[a].category_id = new_cat

    def optimize_profile(self, profile, below, above, cat_b, cat_a):
        cids = self.model.criteria.keys()
        random.shuffle(cids)

        for cid in cids:
            ct = self.ct[profile.id]

            perf_profile = profile.performances[cid]
            perf_above = above.performances[cid]
            perf_below = below.performances[cid]

            h_below = self.compute_below_histogram(cid, perf_profile,
                                                   perf_below, cat_b,
                                                   cat_a, ct)
            h_above = self.compute_above_histogram(cid, perf_profile,
                                                   perf_above, cat_b,
                                                   cat_a, ct)
            h = h_below
            h.update(h_above)

            if not h:
                continue

            i = self.histogram_choose(h, perf_profile)

            r = random.uniform(0, 1)

            if r <= h[i]:
                self.update_tables(profile.id, cid, perf_profile, i)
                profile.performances[cid] = i

    def get_below_and_above_profiles(self, i):
        profiles = self.model.profiles
        bpt = self.model.bpt

        if i == 0:
            below = self.b0
        else:
            below = bpt[profiles[i-1]]

        if i == self.nprofiles-1:
            above = self.bp
        else:
            above = bpt[profiles[i+1]]

        return below, above

    def optimize(self):
        profiles = self.model.profiles
        for i, profile in enumerate(profiles):
            pperfs = self.model.bpt[profile]
            below, above = self.get_below_and_above_profiles(i)
            cat_b, cat_a = self.cat_ranked[i], self.cat_ranked[i+1]
            self.optimize_profile(pperfs, below, above, cat_b, cat_a)

        return self.good / self.na
예제 #23
0
파일: flowsort.py 프로젝트: oso/pymcda
    def get_assignments(self, pt):
        aas = AlternativesAssignments([])
        for ap in pt:
            aas.append(self.get_assignment(ap))

        return aas
예제 #24
0
파일: electre_tri.py 프로젝트: oso/pymcda
 def get_assignments(self, pt):
     aa = AlternativesAssignments()
     for ap in pt:
         a = self.get_assignment(ap)
         aa.append(a)
     return aa