Exemplo n.º 1
0
 def full_update_link_cache(self):
     for (a, b) in self.model.agentgraph.edges_iter():
         (a_id, a_traits) = self.model.get_agent_by_id(a)
         (b_id, b_traits) = self.model.get_agent_by_id(b)
         prob = analysis.calc_probability_interaction_extensible(
             a_traits, b_traits)
         if prob > 0.0 and prob < 1.0:
             #log.debug("active link (%s %s) prob: %s  a_trait: %s  b_trait: %s", a_id, b_id, prob, a_traits, b_traits)
             self.add_pair_to_cache(a_id, b_id)
    def test_probability_interaction_multtree(self):
        focal = set()
        focal.add((40, 41, 44, 53))
        focal.add((280, 283, 290, 313))

        neighbor = set()
        neighbor.add((40, 41, 44, 53))
        neighbor.add((200, 202, 207))

        expected = 0.66667

        prob = analysis.calc_probability_interaction_extensible(focal, neighbor)
        log.info("prob of interaction for mult tree: %s", prob)
        self.assertAlmostEqual(prob, expected, delta=0.01 )
    def test_probability_interaction_multtree(self):
        focal = set()
        focal.add((40, 41, 44, 53))
        focal.add((280, 283, 290, 313))

        neighbor = set()
        neighbor.add((40, 41, 44, 53))
        neighbor.add((200, 202, 207))

        expected = 0.66667

        prob = analysis.calc_probability_interaction_extensible(
            focal, neighbor)
        log.info("prob of interaction for mult tree: %s", prob)
        self.assertAlmostEqual(prob, expected, delta=0.01)
Exemplo n.º 4
0
 def update_link_cache_for_agent(self, agent_id, agent_traits):
     """
     When we perform an action to an agent randomly (e.g., loss or mutation), we need to check ALL of the
     agent's links to neighbors and update the link cache accordingly.
     """
     #log.debug("updating link cache for agent: %s after innovation or loss event", agent_id)
     neighbors = self.model.get_all_neighbors_for_agent(agent_id)
     for neighbor in neighbors:
         (neighbor_id,
          neighbor_traits) = self.model.get_agent_by_id(neighbor)
         prob = analysis.calc_probability_interaction_extensible(
             agent_traits, neighbor_traits)
         if prob == 0.0 or prob == 1.0:
             #log.debug("removing (%s,%s) from active link cache", agent_id, neighbor_id)
             self.remove_pair_from_cache(agent_id, neighbor_id)
         else:
             self.add_pair_to_cache(agent_id, neighbor_id)
Exemplo n.º 5
0
 def get_fraction_links_active(self):
     """
     Calculate the fraction of links whose probability of interaction is neither 1.0 nor 0.0
     """
     active_links = 0
     for (a, b) in self.model.model.edges_iter():
         (a_id, a_traits) = self.model.get_agent_by_id(a)
         (b_id, b_traits) = self.model.get_agent_by_id(b)
         prob = analysis.calc_probability_interaction_extensible(
             a_traits, b_traits)
         if prob > 0.0 and prob < 1.0:
             #log.debug("active link (%s %s) prob: %s  a_trait: %s  b_trait: %s", a_id, b_id, prob, a_traits, b_traits)
             active_links += 1
     num_links_total = self.model.model.number_of_edges()
     #log.debug("active links: %s total links: %s", active_links, num_links_total)
     fraction_active = float(active_links) / num_links_total
     return fraction_active
Exemplo n.º 6
0
    def step(self, timestep):
        """
        Implements a single time step in the Multiple Tree Prerequisites + Learning "semantic" Axelrod model,
        selecting a focal agent at
        random, and then one of the focal agent's neighbors (this rule knows nothing about
        how "neighbors" are represented, so the rule itself is fully generic to many
        population structures, including those with long-distance connections.

        The two agents interact based upon their cultural similarity, measured as set-theoretic overlap regardless
        of the structure of traits themselves.  If the focal agent if F, and a random neighbor is N, then:

        1.  No interaction is possible if F == N, if F.isdisjoint(N), or if N.issubset(F).
        2.  Otherwise with probability equal to the Jaccard index between F and N, interaction occurs.
        3.  The list of traits which N possesses but F does not is constructed, and a random choice made, of T
        4.  If F possesses the prerequisite traits for T, F either adds T, or replaces a random trait of its own.
        5.  Otherwise, with prob equal to the learning rate, F learns the "most foundational" missing prereq for T.
        6.  Otherwise, nothing happens.

        When any change happens to the focal agent, we update the active link cache, either for the single
        agent-neighbor pair involved in the interaction, or all of the agent's links.  This allows model checking
        at the global level to be a simple O(1) operation.
        """

        learning_rate = self.sc.learning_rate
        loss_rate = self.sc.loss_rate
        innov_rate = self.sc.innov_rate

        (agent_id, agent_traits) = self.model.get_random_agent()
        (neighbor_id,
         neighbor_traits) = self.model.get_random_neighbor_for_agent(agent_id)

        # FIXED BUG - WE DO NOT RETURN HERE, WE PASS, BECAUSE WE ALWAYS NEED TO STILL CHECK FOR
        # INNOVATIONS, OTHERWISE (A) INNOVATIONS AREN'T HAPPENING AT THE CONSTANT GIVEN RATE, AND (B)
        # WE CANNOT ESCAPE A CONVERGED STATE THROUGH NOISE
        if agent_traits == neighbor_traits:
            pass
        elif agent_traits.isdisjoint(neighbor_traits):
            pass
        elif neighbor_traits.issubset(agent_traits):
            pass
        else:
            prob = analysis.calc_probability_interaction_extensible(
                agent_traits, neighbor_traits)
            if npr.random() < prob:
                #log.debug("starting interaction")
                neighbor_diff_traits = analysis.get_traits_differing_from_focal_extensible(
                    agent_traits, neighbor_traits)

                # get a random trait from the neighbor that we'd like to try to learn
                # THE ARRAY DEFERENCE IS ESSENTIAL SINCE random.sample returns an array, even with one element.
                rand_trait = random.sample(neighbor_diff_traits, 1)[0]

                if self.model.trait_universe.has_prereq_for_trait(
                        rand_trait, agent_traits) == False:
                    if npr.random() < learning_rate:
                        needed_prereq = self.model.trait_universe.get_deepest_missing_prereq_for_trait(
                            rand_trait, agent_traits)
                        agent_traits.add(needed_prereq)
                        self.model.set_agent_traits(agent_id, agent_traits)
                        #log.debug("agent %s learned prereq %s from agent %s", agent_id, needed_prereq, neighbor_id)

                else:
                    # find a random trait that focal has but the neighbor does not
                    # and we get rid of it, learning the neighbor's trait instead
                    #log.debug("agent: %s neighbor: %s", agent_traits, neighbor_traits)
                    unique_to_focal = agent_traits.difference(neighbor_traits)
                    #log.debug("unique to focal: %s", unique_to_focal)
                    if len(unique_to_focal) > 0:
                        focal_trait_to_replace = random.sample(
                            unique_to_focal, 1)[0]
                        #log.debug("replacing trait %s with %s", focal_trait_to_replace, rand_trait)
                        agent_traits.remove(focal_trait_to_replace)
                    agent_traits.add(rand_trait)
                    self.model.set_agent_traits(agent_id, agent_traits)

                # track the interaction and time, and update the link cache
                self.model.update_interactions(timestep)
                self.update_link_cache_for_agent(agent_id, agent_traits)

        # now we see if somebody forgets something
        if npr.random() < loss_rate:
            (loss_agent_id, loss_agent_traits) = self.model.get_random_agent()
            if len(loss_agent_traits) < 1:
                return
            trait_to_lose = random.sample(loss_agent_traits, 1)[0]
            loss_agent_traits.remove(trait_to_lose)
            self.model.set_agent_traits(loss_agent_id, loss_agent_traits)
            self.model.update_loss_events()
            self.update_link_cache_for_agent(loss_agent_id, loss_agent_traits)

        # now, we see if an innovation happens in the population and perform it if so.
        if npr.random() < innov_rate:
            (innov_agent_id,
             innov_agent_traits) = self.model.get_random_agent()
            random_innovation = self.model.trait_universe.get_random_trait_not_in_set(
                innov_agent_traits)
            path = self.model.trait_universe.get_parents_for_node(
                random_innovation)
            path.append(random_innovation)
            innov_agent_traits.update(path)
            self.model.set_agent_traits(innov_agent_id, innov_agent_traits)
            self.model.update_innovations()
            self.update_link_cache_for_agent(innov_agent_id,
                                             innov_agent_traits)
Exemplo n.º 7
0
    def step(self, timestep):
        """
        Implements a single time step in the Trait-Extensible Axelrod model, selecting a focal agent at
        random, and then one of the focal agent's neighbors (this rule knows nothing about
        how "neighbors" are represented, so the rule itself is fully generic to many
        population structures, including those with long-distance connections.

        The two agents interact based upon their cultural similarity. This is handled as follows:

        1.  When two agents have all traits in common, technically they would interact with probability
        one, but no traits would change.  For speed, this is short-circuited.

        2.  When two agents have no traits in common, the probability of interaction is zero.  Here we
        simply move on, and don't make a random trial because there's no point.

        3.  If the neighbor's trait set is a strict subset of the agent's trait set, there is nothing
        new to adopt, so we move on.

        4.  Otherwise, with probability equal to similarity (or, usually, 1 - dissimilarity), the focal
        agent adopts one of the neighbor's traits for which they are dissimilar.  With probability "addition rate",
        this occurs by adding the neighbor's trait to the focal agent's trait set without replacing an existing trait,
        otherwise, the focal agent replaces a random trait in its existing set by the neighbor's trait.

        """
        add_rate = self.sc.add_rate

        (agent_id, agent_traits) = self.model.get_random_agent()
        (neighbor_id,
         neighbor_traits) = self.model.get_random_neighbor_for_agent(agent_id)

        if agent_traits == neighbor_traits:
            return
        elif agent_traits.isdisjoint(neighbor_traits):
            return
        elif neighbor_traits.issubset(agent_traits):
            return
        else:
            prob = analysis.calc_probability_interaction_extensible(
                agent_traits, neighbor_traits)
            draw = npr.random()
            if draw < prob:
                neighbor_diff_traits = analysis.get_traits_differing_from_focal_extensible(
                    agent_traits, neighbor_traits)
                #log.debug("neighbor_diff_traits: %s", neighbor_diff_traits)
                neighbor_random_diff_trait = random.sample(
                    neighbor_diff_traits, 1)
                add_draw = npr.random()
                if add_draw < add_rate:
                    # we add the neighbor's trait, without replacing an existing trait
                    agent_traits.add(neighbor_random_diff_trait[0])
                    #log.debug("adding trait w/o replacement: %s", neighbor_random_diff_trait[0])
                    self.model.set_agent_traits(agent_id, agent_traits)
                else:
                    # we replace an existing trait with the neighbor's trait
                    focal_trait_to_replace = random.sample(agent_traits, 1)
                    #log.debug("replacing trait %s with %s", focal_trait_to_replace[0], neighbor_random_diff_trait[0])
                    agent_traits.remove(focal_trait_to_replace[0])
                    agent_traits.add(neighbor_random_diff_trait[0])
                    self.model.set_agent_traits(agent_id, agent_traits)

                # track the interaction and time
                self.model.update_interactions(timestep)
            else:
                # no interaction given the random draw and probability, so just return
                #log.debug("no interaction")
                return