<commit_before>"""Monte Carlo Markov Chains with people!"""

from wallace.models import Info, Transformation
from wallace.networks import Chain
from wallace.nodes import Source, Agent
from wallace.experiments import Experiment
from wallace import db
import random
from flask import Blueprint, Response, request
from rq import Queue
from wallace.heroku.worker import conn
import json
from sqlalchemy import Boolean
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.sql.expression import cast
from operator import attrgetter


class MCMCP(Experiment):

    """Define the structure of the experiment."""

    def __init__(self, session):
        """Call the same function in the super (see experiments.py in wallace).

        A few properties are then overwritten.
        Finally, setup() is called.
        """
        super(MCMCP, self).__init__(session)
        self.experiment_repeats = 1
        self.trials_per_participant = 10
        self.network = lambda: Chain(max_size=100)
        self.setup()
        self.agent = MCMCPAgent

    def setup(self):
        """Setup the networks.

        Setup only does stuff if there are no networks, this is so it only
        runs once at the start of the experiment. It first calls the same
        function in the super (see experiments.py in wallace). Then it adds a
        source to each network.
        """
        if not self.networks():
            super(MCMCP, self).setup()
            for net in self.networks():
                VectorSource(network=net)

    def get_network_for_participant(self, participant):
        if len(participant.nodes(failed="all")) < self.trials_per_participant:
            return random.choice(self.networks())
        else:
            return None

    def add_node_to_network(self, node, network):
        """When a node is created it is added to the chain (see Chain in networks.py)
        and it receives any transmissions."""
        network.add_node(node)
        node.receive()

    def recruit(self):
        """Recruit one participant at a time until all networks are full."""
        if self.networks(full=False):
            self.recruiter().recruit_participants(n=1)
        else:
            self.recruiter().close_recruitment()


class MCMCPAgent(Agent):

    __mapper_args__ = {
        "polymorphic_identity": "MCMCP_agent"
    }

    def update(self, infos):
        info = infos[0]
        self.replicate(info)
        new_info = ChoosableInfo(origin=self, contents=self.perturb(json.loads(info.contents)))
        Perturbation(info_in=info, info_out=new_info)

    def perturb(self, l):
        return json.dumps([abs(v + random.random() - 0.5) for v in l])

    def _what(self):
        infos = self.infos()
        return [i for i in infos if i.chosen][0]


class VectorSource(Source):
    """A Source that transmits a random vector."""

    __mapper_args__ = {
        "polymorphic_identity": "random_vector_source"
    }

    def create_information(self):
        """Define the contents of new Infos.

        transmit() -> _what() -> create_information().
        """
        return ChoosableInfo(origin=self, contents=json.dumps([random.random() for i in range(10)]))


class ChoosableInfo(Info):

    __mapper_args__ = {
        "polymorphic_identity": "vector_info"
    }

    @hybrid_property
    def chosen(self):
        try:
            return bool(self.property1)
        except TypeError:
            return None

    @chosen.setter
    def chosen(self, chosen):
        """Assign chosen to property1."""
        self.property1 = repr(chosen)

    @chosen.expression
    def chosen(self):<commit_msg>Create and use an AnimalSource<commit_after>"""Monte Carlo Markov Chains with people!"""

from wallace.models import Info, Transformation
from wallace.networks import Chain
from wallace.nodes import Source, Agent
from wallace.experiments import Experiment
from wallace import db
import random
from flask import Blueprint, Response, request
from rq import Queue
from wallace.heroku.worker import conn
import json
from sqlalchemy import Boolean
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.sql.expression import cast
from operator import attrgetter


class MCMCP(Experiment):

    """Define the structure of the experiment."""

    def __init__(self, session):
        """Call the same function in the super (see experiments.py in wallace).

        A few properties are then overwritten.
        Finally, setup() is called.
        """
        super(MCMCP, self).__init__(session)
        self.experiment_repeats = 1
        self.trials_per_participant = 10
        self.network = lambda: Chain(max_size=100)
        self.setup()
        self.agent = MCMCPAgent

    def setup(self):
        """Setup the networks.

        Setup only does stuff if there are no networks, this is so it only
        runs once at the start of the experiment. It first calls the same
        function in the super (see experiments.py in wallace). Then it adds a
        source to each network.
        """
        if not self.networks():
            super(MCMCP, self).setup()
            for net in self.networks():
                AnimalSource(network=net)

    def get_network_for_participant(self, participant):
        if len(participant.nodes(failed="all")) < self.trials_per_participant:
            return random.choice(self.networks())
        else:
            return None

    def add_node_to_network(self, node, network):
        """When a node is created it is added to the chain (see Chain in networks.py)
        and it receives any transmissions."""
        network.add_node(node)
        node.receive()

    def recruit(self):
        """Recruit one participant at a time until all networks are full."""
        if self.networks(full=False):
            self.recruiter().recruit_participants(n=1)
        else:
            self.recruiter().close_recruitment()


class MCMCPAgent(Agent):

    __mapper_args__ = {
        "polymorphic_identity": "MCMCP_agent"
    }

    def update(self, infos):
        info = infos[0]
        self.replicate(info)
        new_info = ChoosableInfo(origin=self, contents=self.perturb(json.loads(info.contents)))
        Perturbation(info_in=info, info_out=new_info)

    def perturb(self, l):
        return json.dumps([abs(v + random.random() - 0.5) for v in l])

    def _what(self):
        infos = self.infos()
        return [i for i in infos if i.chosen][0]


class AnimalSource(Source):
    """A source that transmits animal shapes."""

    __mapper_args__ = {
        "polymorphic_identity": "animal_source"
    }

    def _contents(self):
        data = {}

        for i in range(20):
            data["animal_" + str(i)] = {
                "foot_spread": random.uniform(0, 1),
                "body_height": random.uniform(0.1, 1.5),
                "body_tilt": random.uniform(-15, 45),
                "tail_length": random.uniform(0.05, 1.2),
                "tail_angle": random.uniform(-45, 190),
                "neck_length": random.uniform(0, 2.5),
                "neck_angle": random.uniform(90, 180),
                "head_length": random.uniform(0.05, 0.75),
                "head_angle": random.uniform(5, 80)
            }

        return json.dumps(data)

    def create_information(self):
        """Define the contents of new Infos.

        transmit() -> _what() -> create_information().
        """
        return ChoosableInfo(origin=self, contents=self._contents())


class ChoosableInfo(Info):

    __mapper_args__ = {
        "polymorphic_identity": "vector_info"
    }

    @hybrid_property
    def chosen(self):
        try:
            return bool(self.property1)
        except TypeError:
            return None

    @chosen.setter
    def chosen(self, chosen):
        """Assign chosen to property1."""
        self.property1 = repr(chosen)

    @chosen.expression
    def chosen(self):
{'fraction_non_alphanumeric': 0.09891359272359777, 'fraction_numerical': 0.008716523496715513, 'mean_word_length': 2.5359535506922732, 'pattern_counts': {'":': 15, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7030771', 'n_tokens_mistral': 2375, 'n_tokens_neox': 2231, 'n_words': 668}