Created
May 7, 2024 16:14
-
-
Save qgustavor/478e9c4db34244b200ac27e268546d46 to your computer and use it in GitHub Desktop.
Population model to simulate what could happen if two female woman could have female children together and children had 95% chance of inheriting their parents' sexuality
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Function to interpolate missing rates | |
function interpolateRate(rates, age) { | |
const surroundingRates = Object.entries(rates) | |
.filter(([key]) => Number(key) <= age) | |
.sort((a, b) => Number(a[0]) - Number(b[0])) // Sort by age (ascending) | |
if (surroundingRates.length === 0) { | |
// No rates available, return 0 (adjust as needed) | |
return 0 | |
} | |
const closestRate = surroundingRates.pop() // Get the closest rate (highest age) | |
const closestAge = Number(closestRate[0]) | |
const closestValue = closestRate[1] | |
if (age === closestAge) { | |
return closestValue | |
} | |
// Linear interpolation between closest rates (adjust for different interpolation methods if needed) | |
const previousRate = surroundingRates.length > 0 ? surroundingRates.pop()[1] : closestValue | |
const ageDiff = closestAge - (surroundingRates.length > 0 ? Number(surroundingRates.pop()[0]) : 0) | |
const rateDiff = closestValue - previousRate | |
const ageRatio = (age - closestAge) / ageDiff | |
return closestValue - (ageRatio * rateDiff) | |
} | |
function simulatePopulation (options = {}) { | |
const { | |
initialMales = 1000, | |
initialFemales = 1000, | |
generations = 1000, | |
mortalityRates = { 0: 0.001, 20: 0.002, 80: 0.07, 150: 1 }, | |
fertilityRates = { 0: 0, 10: 0, 15: 0.1, 20: 0.4, 30: 0.5, 40: 0.2, 50: 0.1, 60: 0 }, | |
sexualityInheritRate = 0.95, | |
newCoupleRate = 0.3 | |
} = options | |
const population = [] | |
// Initialize population with individuals and age | |
for (let i = 0; i < initialMales; i++) { | |
population.push({ gender: 'male', age: 0, sexuality: 'heterosexual' }) | |
} | |
for (let i = 0; i < initialFemales; i++) { | |
population.push({ gender: 'female', age: 0, sexuality: 'heterosexual' }) | |
} | |
for (let generation = 0; generation < generations; generation++) { | |
// Age individuals | |
for (let j = 0; j < population.length; j++) { | |
population[j].age++ | |
} | |
// Form couples (considering sexuality) | |
const singles = population.filter((individual) => !individual.partner) | |
const potentialCouples = Math.floor(singles.length / 2) | |
const newCouples = Math.min(potentialCouples, Math.floor(potentialCouples * newCoupleRate)) | |
for (let j = 0; j < newCouples; j++) { | |
let maleIndex, femaleIndex | |
let attempts = 0 // Counter for loop attempts | |
do { | |
attempts++ | |
maleIndex = Math.floor(Math.random() * singles.length) | |
femaleIndex = (maleIndex + 1) % singles.length | |
} while ( | |
singles[maleIndex].gender === singles[femaleIndex] || | |
singles[maleIndex] === singles[femaleIndex] || | |
attempts > 10 | |
) | |
// If attempts limit is reached, skip remaining partner assignments | |
if (attempts > 10) break | |
if (singles[maleIndex].gender === 'male' && singles[femaleIndex].gender === 'female') { | |
// Opposite sex couple, both can be potential partners | |
if (singles[maleIndex].sexuality === 'heterosexual' && singles[femaleIndex].sexuality === 'heterosexual') { | |
singles[maleIndex].partner = singles[femaleIndex] | |
singles[femaleIndex].partner = singles[maleIndex] | |
} | |
} else if (singles[maleIndex].gender === 'female' && singles[femaleIndex].gender === 'female') { | |
// Same-sex female couple (both homosexual for simplicity) | |
if (singles[maleIndex].sexuality === 'homosexual' && singles[femaleIndex].sexuality === 'homosexual') { | |
singles[maleIndex].partner = singles[femaleIndex] | |
singles[femaleIndex].partner = singles[maleIndex] | |
} | |
} | |
} | |
// Handle births with age-specific fertility and gender determination | |
const couples = population.filter((individual) => individual.partner).map(individual => [individual, individual.partner]) | |
const newBirths = Math.floor( | |
couples.reduce((totalBirths, couple) => { | |
const fertilityRate = interpolateRate(fertilityRates, couple[0].age) | |
return totalBirths + fertilityRate | |
}, 0) | |
) | |
for (let j = 0; j < newBirths; j++) { | |
const couple = couples[Math.floor(Math.random() * couples.length)] | |
const childGender = couple[0].gender === 'female' && couple[1].gender === 'female' | |
? 'female' // Female-only couple, child is always female (XX) | |
: Math.random() < 0.5 ? 'male' : 'female' // Random gender for heterosexual couples | |
population.push({ | |
gender: childGender, | |
partner: null, | |
age: 0, | |
sexuality: Math.random() < sexualityInheritRate // Child inherits parents' sexuality with 80% chance | |
? couple[0].sexuality || couple[1].sexuality // Handle potential missing sexuality | |
: couple[0].sexuality === 'heterosexual' ? 'homosexual' : 'heterosexual', // Opposite of parents' | |
}) | |
} | |
// Handle deaths with age-specific mortality | |
const deceased = [] | |
for (let j = 0; j < population.length; j++) { | |
const individual = population[j] | |
const mortalityRate = interpolateRate(mortalityRates, individual.age) | |
if (Math.random() < mortalityRate) { | |
deceased.push(individual) | |
if (individual.partner) { | |
individual.partner.partner = null // Set partner to null if deceased has one | |
} | |
} | |
} | |
for (const individual of deceased) { | |
population.splice(population.indexOf(individual), 1) | |
} | |
const totalPopulation = population.length | |
const malePopulation = population.filter(e => e.gender === 'male').length | |
const femalePopulation = population.filter(e => e.gender === 'female').length | |
console.log({ generation, totalPopulation, malePopulation, femalePopulation }) | |
} | |
return population | |
} | |
// Example usage | |
simulatePopulation() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment