C# :: Aufgabe #267

2 Lösungen Lösungen öffentlich

Entwicklung einer Population bishin zur vollständigen Verwandtschaft

Anfänger - C# von hollst - 04.11.2019 um 12:38 Uhr
Gegeben sei eine Startpopulation mit 2N Mitgliedern (z. B. N = 100), N männliche und N weibliche, die N Elternpaare bilden.

Jedes Elternpaar erzeuge genau einen männlichen und einen weiblichen Nachkommen. Diese 2N Nachkommen bilden
anschließend durch Vermischung die nächste Generation von Eltern und so fort bis zur Generation g, die natürlich wieder 2N Populationsmitglieder hat.

Bei einer Vermischung sei Inzest (Bruder-Schwester-Ehe) verboten, eine Ehe zwischen Cousin und Cousine allerdings erlaubt.

Mittels Computersimulation sind zwei Fragen zu beantworten:

Die erste Frage lautet, nach wie vielen Generationen (g1) ist (im Mittel) erstmals ein Nachkomme mit allen Populationsmitgliedern
seiner Generation verwandt.

Die zweite Frage lautet, nach wie vielen Generationen (g2) ist (im Mittel) jeder Nachkomme mit allen Populationsmitgliedern
seiner Generation verwandt.

Viel Spaß!

Lösungen:

vote_ok
von hollst (13980 Punkte) - 06.11.2019 um 17:01 Uhr
Quellcode ausblenden C#-Code
using static System.Console;

using COGNATION;

namespace COGNITION_CONSOLE
{
    static class Program
    {
        static void Main()
        {
            int counter = 0, g1 = 0, g2 = 0;
            int NumberOfPopulation = 250, max_loops = 10000;
            while (counter < max_loops)
            {
                COGNATION.GenerationSequence gs = new GenerationSequence(NumberOfPopulation);
                g1 += gs.g1;
                g2 += gs.g2;
                counter++;
                $"g1: {gs.g1}   ng1: {gs.ng1}   g2: {gs.g2}    NumberOfPopulation: {NumberOfPopulation}".Info();
                WriteLine(1.0 * g1 / counter);
                WriteLine(1.0 * g2 / counter);
                $"loops: {counter}".Info();
            }
            "ready".PressKey();
        }
    }
}


Quellcode ausblenden C#-Code
using System;
using System.Collections.Generic;
using System.Text;

using static System.Console;

namespace COGNATION
{
    public class ShuffleClass         //Fisher - Yates shuffle
    {
        private readonly Random rand;
        private readonly bool bo_reset;
        private readonly bool bo_all;
        private readonly int count_cards;

        public int[] Mix { get; private set; }
        public ShuffleClass(int count_cards, bool bo_reset = false, bool bo_all = false)
        {
            this.count_cards = count_cards;
            this.rand = new Random();
            this.bo_all = bo_all;
            this.bo_reset = bo_reset;
            this.Mix = new int[count_cards];
        }

        public void Shuffle()
        {
            for (var i = 0; i < count_cards; i++)
                this.Mix[i] = i;
            if (bo_reset)
                return;

            Stack<int> stack = new Stack<int>();
            for (var j = Mix.Length - 1; j > 0; j--)
            {
                int jj = rand.Next(j + 1);
                if (bo_all && (jj == j)) //Inzest verboten
                    j += 1;//Auslosung wiederholen
                else
                {
                    stack.Push(Mix[jj]);
                    Mix[jj] = Mix[j];
                    Mix[j] = stack.Pop();
                }
            }
        }
    }

    public class GenerationSequence
    {
        public bool[][] result;
        public int g1, g2, ng1;
        public GenerationSequence(int NumberOfPopulation)
        {
            result = new bool[NumberOfPopulation][];
            g1 = 0;
            g2 = 0;
            ng1 = -1;

            for (var i = 0; i < NumberOfPopulation; i++)
            {
                result[i] = new bool[NumberOfPopulation];
                result[i][i] = true;//Zunächst ist jeder nur mit sich selber verwandt.
            }

            bool[][] result_old = result.DeepCopy();
            int generation_counter = 0;

            ShuffleClass s = new ShuffleClass(NumberOfPopulation, bo_all: true);

            bool bo_ready = false;
            while (!bo_ready)
            {
                s.Shuffle();
                for (var i = 0; i < NumberOfPopulation; i++)
                    for (var j = 0; j < NumberOfPopulation; j++)
                        result[i][j] = result_old[i][j] | result_old[s.Mix[i]][j];
                result_old = result.DeepCopy();
                generation_counter++;

                int z2 = 0;
                for (var i = 0; i < NumberOfPopulation; i++)
                {
                    int z1 = 0;
                    for (var j = 0; j < NumberOfPopulation; j++)
                        if (result[i][j])
                            z1++;
                    if (z1 == NumberOfPopulation)
                    {
                        if (g1 == 0)
                        { 
                            g1 = generation_counter;
                            ng1 = i;
                        }
                        z2++;                        
                    }
                }
                if (z2 == NumberOfPopulation)
                    g2 = generation_counter;
                bo_ready = g2 != 0;
            }
        }
    }

    public static class Extentions
    {
        public static void PressKey(this string s)
        {
            WriteLine(s); ReadKey();
        }

        public static void Info(this string s) =>   WriteLine(s);

        public static bool[][] DeepCopy(this bool[][] b)
        {
            bool[][] result = new bool[b.Length][];
            for(var i = 0; i < result.Length; i++)
            {
                result[i] = new bool[b[i].Length];
                for (var j = 0; j < result[i].Length; j++)
                    result[i][j] = b[i][j];
            }
            return result;
        }
    }
}
vote_ok
von daniel59 (4260 Punkte) - 19.12.2019 um 15:04 Uhr
Quellcode ausblenden C#-Code
using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsolePopulation
{
    class Program
    {
        static Random rnd = new Random();
        static void Main(string[] args)
        {
            int n;
            int simulations;
            Console.WriteLine("----- Simulation einer Population -----");
            Console.Write("Startpopulation (n): ");
            if (int.TryParse(Console.ReadLine(), out n) && n > 1)
            {
                Console.Write("Anzahl Simulationen: ");
                if (int.TryParse(Console.ReadLine(), out simulations) && simulations > 0)
                {
                    int owe, ewe;

                    int[] resultsOwe = new int[simulations];
                    int[] resultsEwe = new int[simulations];

                    for (int i = 0; i < simulations; i++)
                    {
                        Console.WriteLine($"Simulation {i + 1} gestartet");
                        SimulatePopulation(n, out owe, out ewe);
                        resultsOwe[i] = owe;
                        resultsEwe[i] = ewe;
                    }

                    double avgOwe = resultsOwe.Average();
                    double avgEwe = resultsEwe.Average();

                    Console.WriteLine($"Nach {avgOwe} Generationen ist im Mittel mindestens eine Person mit allen verwandt.");
                    Console.WriteLine($"Nach {avgEwe} Generationen ist im Mittel mindestens jede Person mit allen verwandt.");
                }
            }
            Console.WriteLine("Simulation beendet");
            Console.ReadLine();
        }

        static void SimulatePopulation(int n, out int generationOneWithEveryone, out int generationEveryoneWithEveryOne)
        {
            generationOneWithEveryone = 0;
            generationEveryoneWithEveryOne = 0;

            var start = CreateStartPopulation(n);
            int generation = 1;

            IEnumerable<Person> current = start;

            IEnumerable<Person> oneWithEveryone = null;
            IEnumerable<int> everyoneWithEveryOne = null;

            while (oneWithEveryone == null || everyoneWithEveryOne == null)
            {
                generation++;
                current = Populate(current);

                if (oneWithEveryone == null)
                {
                    var owe = CheckRelationsOneWithEveryone(current);
                    if (owe.Count() > 0)
                    {
                        oneWithEveryone = owe;
                        generationOneWithEveryone = generation;
                    } 
                }

                if (everyoneWithEveryOne == null)
                {
                    var ewe = CheckRelationsEveryoneWithEveryone(current);
                    if (ewe.Count() > 0)
                    {
                        everyoneWithEveryOne = ewe;
                        generationEveryoneWithEveryOne = generation;
                    } 
                }
            }
        }

        static IEnumerable<Person> CreateStartPopulation(int n)
        {
            for (int i = 1; i <= n * 2; i++)
            {
                yield return new Person() { Gender = (Gender)(i & 1), DNA = new int[1] { i }, Generation = 1 };
            }
        }

        static IEnumerable<Person> Populate(IEnumerable<Person> currentPopulation)
        {
            var women = currentPopulation.Where(a => a.Gender == Gender.Female);
            List<Person> men = currentPopulation.Where(a => a.Gender == Gender.Male).ToList();

            IEnumerable<Person> newPopulation = new Person[0];

            foreach (var woman in women)
            {
                Person man;
                do
                {
                    if (men.Count == 1 && men.First().DNA.SequenceEqual(woman.DNA))
                    {
                        return Populate(currentPopulation);
                    }

                    int index = rnd.Next(0, men.Count);
                    man = men[index];

                } while (man.DNA.SequenceEqual(woman.DNA));

                men.Remove(man);

                var children = woman.GetChildrenWith(man);
                newPopulation = newPopulation.Concat(children);

            }

            return newPopulation;
        }

        static IEnumerable<Person> CheckRelationsOneWithEveryone(IEnumerable<Person> population)
        {
            return population.Where(a => population.All(b => b.DNA.Intersect(a.DNA).Count() > 0));
        }

        static IEnumerable<int> CheckRelationsEveryoneWithEveryone(IEnumerable<Person> population)
        {
            IEnumerable<int> intersection = population.First().DNA;
            foreach (var person in population.Skip(1))
            {
                intersection = intersection.Intersect(person.DNA);
                if (intersection.Count() == 0)
                { break; }
            }

            return intersection;
        }
    }

    enum Gender : int
    {
        Female,
        Male
    }

    class Person
    {
        public Gender Gender { get; set; }
        public int[] DNA { get; set; }
        public int Generation { get; set; }

        public bool AllowMarriage(Person p)
        {
            return !DNA.SequenceEqual(p.DNA) && Gender != p.Gender && Generation == p.Generation;
        }

        public IEnumerable<Person> GetChildrenWith(Person p)
        {
            if (!AllowMarriage(p))
            {
                throw new ArgumentException();
            }

            int[] newDNA = DNA.Concat(p.DNA).ToArray();
            yield return new Person() { Gender = Gender.Female, DNA = newDNA, Generation = Generation + 1 };
            yield return new Person() { Gender = Gender.Male, DNA = newDNA, Generation = Generation + 1 };
        }

        public override string ToString()
        {
            string s = "";
            foreach (int i in DNA)
            {
                s += $"{i},";
            }
            if (!string.IsNullOrEmpty(s))
            {
                s = s.Substring(0, s.Length - 1);
            }

            s += $" {Gender}";

            return s;
        }

        public override bool Equals(object obj)
        {
            Person p = (Person)obj;

            return Gender == p.Gender
                && DNA.SequenceEqual(p.DNA);
        }

        public override int GetHashCode()
        {
            int hash = 13;

            hash = (hash * 7) + Gender.GetHashCode();
            hash = (hash * 7) + DNA.GetHashCode();

            return hash;
        }
    }
}