Workspace
Jonathan Brooks/

Dynamic Quorum in Python

0
Beta
Spinner

Dynamic Quorum in Python

This protocol initializes quorum for each voting round as 2/3 the average of past voting round quorums (or a bare minimum, whichever is higher). The intended use case of this program is human voting, though the underlying logic is useful for machine learning models reaching consensus and many other scenarios.

It also increments the quorum higher, if indecision (abstention) is excessive ('idk' votes over 1/2 of total votes after initial quorum is met).

This quorum automatically adjusts to, and allows for fluctuations in engagement, while requiring a minimum of informed engagement, mitigating minority rule and gridlock.

Further development can be done, to increase the dynamism, by using the past quorums, turnouts and ratio of motions that pass or fail to those that stall, to adjust with increasing granularity by automatically tuning with hyperparameters. As the dataset of prior voting rounds grows, the responsiveness to changing conditions does too, so optimization for engagement and decisiveness perpetually improves.

What are pros and cons to algorithmically adjusting quorum instead of manually setting it?

Pros:

  • a consistent protocol eliminates the potential of arbitrary manipulation.
  • a well designed dynamic quorum needs no manual intervention.
    Cons:
  • many people are suspicious of computerized voting.
  • it doesn't eliminate the problem of a majority for tyranny.
import asyncio
import nest_asyncio
import json

nest_asyncio.apply()


class DynamicQuorum:
    def __init__(self):
        self.past_quorums = self.load_past_quorums()
        self.quorum = self.init_quorum()
        self.votes = []

        
    def init_quorum(self):
        if not self.past_quorums:
            return 10  # Default quorum if no past turnouts
        else:
            average_quorum = sum(self.past_quorums) / len(self.past_quorums)
        return max(int((2/3) * average_quorum), 10)

    def load_past_quorums(self):
        try:
            with open("past_quorums.json", "r") as file:
                return json.load(file)
        except (FileNotFoundError, json.JSONDecodeError):
            return []

    def save_past_quorums(self):
        with open("past_quorums.json", "w") as file:
            json.dump(self.past_quorums, file)
            
    async def gather_votes(self):
        quorum_met_once = False  # Flag to track whether the quorum has been met at least once
        while True:
            vote = await self.get_vote()
            self.votes.append(vote.lower())

            yay_count = self.votes.count('yay')
            nay_count = self.votes.count('nay')
            idk_count = self.votes.count('idk')
            yay_nay_sum = yay_count+nay_count
            total_votes = len(self.votes)

            print(f"Vote received: {vote}, Current Votes - 'yay': {yay_count}, 'nay': {nay_count}, 'idk': {idk_count}, Dynamic Quorum: {self.quorum}")

            if yay_count > nay_count * 2 and yay_nay_sum > idk_count and total_votes >= self.quorum:
                print(f"Majority (over 2:1 'yay' {yay_count} : 'nay' {nay_count}) passes the motion with quorum at {self.quorum} and below 1:2 indecision ('idk' {idk_count} : 'yay' & 'nay' {yay_nay_sum}). Ending voting.")
                break
            elif nay_count > yay_count * 2 and yay_nay_sum > idk_count and total_votes >= self.quorum:
                print(f"Majority over 2:1 ('nay' {nay_count} : 'yay' {yay_count}) fails the motion with quorum at {self.quorum} and under 1:1 indecision ('idk' {idk_count}: 'yay' & 'nay' {yay_nay_sum}). Ending voting.")
                break
            elif quorum_met_once == True and idk_count > yay_nay_sum * 2:
                print(f"Indecisive vote majority over 2:1 ('idk' {idk_count} : 'nay' & 'yay' {yay_nay_sum}) stalls the motion with quorum at {self.quorum}, 'nay' votes at {nay_count}, and 'yay' votes at {yay_count}. Ending voting.")
                break
            elif quorum_met_once == True and idk_count > yay_nay_sum:
                print(f"Indecisive to decisive ratio is over 1:1 ('idk' {idk_count} : 'nay' & 'yay' {yay_nay_sum}). Raising quorum.")
                self.raise_quorum_if_idk_high()
            elif total_votes >= self.quorum:
                quorum_met_once = True
        return self.votes


    async def get_vote(self):
        while True:
            vote = input("Enter your vote ('yay', 'nay', or 'idk'): ").lower()
            if vote in ('yay', 'nay', 'idk'):
                return vote
            else:
                print("Invalid vote. Please enter 'yay', 'nay', or 'idk'.")

                
    def raise_quorum_if_idk_high(self):
        self.quorum += 1
        print(f"Quorum raised to {self.quorum}")

        
    def finalize_voting(self):
        yay_count = self.votes.count('yay')
        nay_count = self.votes.count('nay')
        idk_count = self.votes.count('idk')
        yay_nay_sum = yay_count+nay_count
        total_votes = len(self.votes)
        self.past_quorums.append(self.quorum)
        self.save_past_quorums() 
        if yay_count > 2 * nay_count and idk_count < total_votes / 2 and total_votes >= self.quorum:
            print(f"The motion passed with {yay_count} yays to {nay_count} nays, and {idk_count} idks.")
        elif nay_count > 2 * nay_count and idk_count < total_votes / 2 and total_votes >= self.quorum:
            print(f"The winner failed with {nay_count} nays to {yay_count} yays, and {idk_count} idks.")
        else:
            print("No clear winner. Voting inconclusive.")


async def main():
    '''This is a Dynamic Quorum protocol that initializes quorum for each voting round at 2/3 the mean average of prior voting round quorums (or a minimum, which could be tuned with hyperparameters, whichever is higher). The intended use case of this program is human voting, though the underlying logic can be useful for machine learning models reaching consensus and many other scenarios.
    
    It also increments the quorum higher, if indecision (abstention) is excessive ('idk' votes over 1/2 of total votes  after initial quorum is met). 
    
    This quorum automatically adjusts to, and allows for fluctuations in engagement, while requiring a minimum of informed engagement, mitigating minority rule and gridlock. If the initial quorum is reached, and abstentions ('idk' votes) are above 1/2.
    
        
    What are pros and cons to algorithmically adjusting quorum instead of manually setting it?
    
    Pros: a consistent protocol eliminates the potential of arbitrary manipulation.
    Cons: many people are suspicious of computerized voting. 
    '''  

    dynamic_quorum = DynamicQuorum()

    print(f"Current quorum: {dynamic_quorum.quorum}")

    # Step 1: Gather votes until conditions are met
    await dynamic_quorum.gather_votes()

    # Step 2: Finalize voting and announce the winner if 'yay' or 'nay' is above 2/3 of new votes
    dynamic_quorum.finalize_voting()

    
if __name__ == '__main__':
    # Run the event loop
    asyncio.run(main())
    
  • AI Chat
  • Code