oTree Forum >

set_group_matrix

#1 by Rita

hello everyone
At present, I am conducting a transaction experiment. I plan to have four participants, two in each group, one seller and one buyer. In the first round, I will randomly assign roles according to the system, that is, [1,2], [3,4]. In the second round, I plan to use set_group_matrix to rearrange groups [1,4], [3,2]. But after I use set_group_matrix, the second round will not work. I want to know which part of my team is wrong.
Thank you everyone

Here is my code
from otree.api import *

class Constants(BaseConstants):
    name_in_url = 'trading_experiment'
    players_per_group = 2
    num_rounds = 2
    num_groups = 2
    SELLER_ROLE = '卖家'
    BUYER_ROLE = '买家'
    room_name = 'room1'
    cost = 10
    quality_average = 65

class Subsession(BaseSubsession):
    def creating_session(self):
        print(f"Creating session for round {self.round_number}")
        if self.round_number == 1:
            print(f"Round {self.round_number} initial group matrix: {self.get_group_matrix()}")
        # 不在这里处理第二轮的重排

class Group(BaseGroup):
    seller_decision_quality = models.IntegerField()
    seller_decision_price = models.CurrencyField()

class Player(BasePlayer):
    quality = models.IntegerField(
        label="商品的品质:",
        min=60, max=70
    )
    price = models.CurrencyField(
        label="商品的价格:",
        min=0
    )
    quality_buyer = models.IntegerField(
        label="买家实际收到商品的品质:",
        min=-10, max=10
    )
    purchase_decision = models.BooleanField(
        label="你是否购买这个商品?",
        choices=[
            [True, '购买'],
            [False, '不购买']
        ],
        widget=widgets.RadioSelect
    )

class Introduction(Page):
    @staticmethod
    def vars_for_template(player: Player):
        return {
            'role': player.role
        }

class SellerDecision(Page):
    form_model = 'player'
    form_fields = ['quality', 'price']

    @staticmethod
    def is_displayed(player):
        return player.role == Constants.SELLER_ROLE

    @staticmethod
    def before_next_page(player: Player, timeout_happened):
        group = player.group
        group.seller_decision_quality = player.quality
        group.seller_decision_price = player.price

class SellerWaitPage(WaitPage):
    @staticmethod
    def is_displayed(player):
        return player.role == Constants.BUYER_ROLE

    @staticmethod
    def after_all_players_arrive(group: Group):
        pass

class BuyerView(Page):
    @staticmethod
    def is_displayed(player):
        return player.role == Constants.BUYER_ROLE

    @staticmethod
    def vars_for_template(player: Player):
        group = player.group
        return {
            'quality': group.seller_decision_quality,
            'price': group.seller_decision_price,
        }

class BuyerDecision(Page):
    form_model = 'player'
    form_fields = ['purchase_decision']

    @staticmethod
    def is_displayed(player):
        return player.role == Constants.BUYER_ROLE

    @staticmethod
    def vars_for_template(player: Player):
        group = player.group
        return {
            'quality': group.seller_decision_quality,
            'price': group.seller_decision_price,
        }

class BuyerQuality(Page):
    form_model = 'player'
    form_fields = ['quality_buyer']

    @staticmethod
    def is_displayed(player: Player):
        return player.role == Constants.BUYER_ROLE and player.purchase_decision

    @staticmethod
    def vars_for_template(player: Player):
        group = player.group
        return {
            'seller_quality': group.seller_decision_quality,
            'seller_price': group.seller_decision_price,
            'player': player
        }

class ResultsWaitPage(WaitPage):
    def after_all_players_arrive(self):
        pass

class SellerResults(Page):
    @staticmethod
    def is_displayed(player):
        return player.role == Constants.SELLER_ROLE

    @staticmethod
    def vars_for_template(player: Player):
        group = player.group
        buyer = group.get_player_by_role(Constants.BUYER_ROLE)
        return {
            'quality': group.seller_decision_quality,
            'price': group.seller_decision_price,
            'buyer_decision': '是' if buyer.purchase_decision else '否',
            'quality_buyer': buyer.quality_buyer if buyer.purchase_decision else '无'
        }

class Results(Page):
    @staticmethod
    def vars_for_template(player: Player):
        group = player.group
        buyer = group.get_player_by_role(Constants.BUYER_ROLE)
        seller = group.get_player_by_role(Constants.SELLER_ROLE)

        if buyer.purchase_decision:
            buyer_benefit = group.seller_decision_quality + buyer.quality_buyer - group.seller_decision_price
            seller_benefit = group.seller_decision_price - Constants.cost
        else:
            buyer_benefit = 0
            seller_benefit = 0

        return {
            'seller_quality': group.seller_decision_quality,
            'seller_price': group.seller_decision_price,
            'buyer_decision': '是' if buyer.purchase_decision else '否',
            'quality_buyer': buyer.quality_buyer if buyer.purchase_decision else '无',
            'buyer_benefit': buyer_benefit,
            'seller_benefit': seller_benefit
        }

class GroupRearrangeWaitPage(WaitPage):
    wait_for_all_groups = True

    @staticmethod
    def after_all_players_arrive(subsession: Subsession):
        if subsession.round_number == 2:
            new_structure = [
                [1, 4], [3, 2]
            ]
            subsession.set_group_matrix(new_structure)
            print(f"Round {subsession.round_number} new group matrix: {subsession.get_group_matrix()}")



page_sequence = [
    Introduction,
    SellerDecision,
    SellerWaitPage,
    BuyerView,
    BuyerDecision,
    BuyerQuality,
    ResultsWaitPage,
    SellerResults,
    Results,
    GroupRearrangeWaitPage  # 将重新分组的 WaitPage 添加到页面序列的最后
]

#2 by Daniel_Frey

Each round is its own subsession, so at the end of round 1 you change the group matrix of subsession 1, but not in subsession 2.

You can set the group matrix in your creating_session-function, since it will run once for each round (i.e. subsession).

Furthermore, are you using oTree 5 or oTree 3?

If you're using oTree 5, creating_session should be placed at the same level as the Subsession-class, not in it:

class Subsession(BaseSubsession):
    pass
    
def creating_session(subsession: Subsession):
    if subsession.round_number == 1:
        print(f"Round {self.round_number} initial group matrix: {self.get_group_matrix()}")
        # 不在这里处理第二轮的重排
    
    if subsession.round_number == 2:
        new_structure = [
            [1, 4], [3, 2]
        ]
        subsession.set_group_matrix(new_structure)
        print(f"Round {subsession.round_number} new group matrix: {subsession.get_group_matrix()}")

#3 by Rita

I am using otree 5, thank you, I know how to do it now and it works.

Write a reply

Set forum username