Моделируем квантовую запутанность на C#

habr.png

Поскольку тема квантовой запутанности всплывает все чаще, захотелось немного углубиться. Судя по комментариям к статьям о квантовой запутанности, не мне одному будет полезна данная информация. Ну и, с учетом того что для большинства из нас программный код гораздо удобнее всяких аллегорий — решено было представить мое понимание в виде кода.
Данная статья расширяет статью другого автора «Квантовая запутанность для чайников» (рекомендую к прочтению, она мне очень помогла). В своей статье indomit привел пример программы, которая наглядно демонстрирует проблему теории скрытых параметров, но не смог привести пример кода для частиц в суперпозиции. В данной же статье мы попытаемся смоделировать 2 случая:

  1. Как бы вели себя запутанные частицы при детерминизме, когда состояние частиц установлено до измерения, просто мы его не можем измерить без внесения искажений (та самая теория скрытых параметров). Получим числа и увидим расхождение с практикой.
  2. Напишем модель запутанных частиц, находящихся в суперпозиции (состояние частиц не определено до измерения). Попробуем предположить, как частица запрограммирована внутри, то есть подгоним ее код под данные, которые получены экспериментально.


За основу статьи взято популярное объяснение феномена квантовой запутанности от Мермина:

Объяснение парадокса по Мермину
Для популярного донесения парадокса Д. Мермин предлагает сконструировать простое устройство[23]. Устройство должно состоять из излучателя частиц и двух детекторов. Две одинаковые частицы испускаются к каждому из них. Поймав частицу, детектор даёт двоичный ответ (0 или 1), зависящий от частицы и своего трёхпозиционного переключателя настройки. Детектирование пары частиц должно дать одинаковые ответы:
  1. Всякий раз, когда детекторы настроены одинаково.
  2. По статистике в половине случаев, когда они настроены случайным образом.

Первое свойство требует, чтобы все детекторы использовали одну и ту же кодировку позиция переключателя ∈ {1,2,3} ↦ отклик ∈ {0,1}, без какого бы то ни было элемента случайности. То есть они должны заранее сговориться какой из откликов, 0 или 1, давать на позицию переключателя, выбрав для каждой частицы одну из восьми возможных функций, 000, 001, 010, 011, 100, 101, 110 и 111. Выбор 000 или 111 приведёт к 100% совпадению показаний детекторов вне зависимости от положения ручки настройки. Если же детекторы реализуют одну из шести оставшихся функций, одна из цифр вытягивается случайно настроенным переключателем в 2/3 случаев, другая — с вероятностью ⅓. Вероятность совпадения двух ответов при этом составит (⅔)² + (⅓)² = 5/9. Так что каков бы ни был алгоритм автомата, корреляция неизбежно превышает 50%, нарушая второе требование.

Но поскольку такую машину всё-таки соорудить можно (например, располагая позиции поляризаторов под 120° как в опыте Бома), то никакого детерминизма (параметров) не может быть даже в скрытой форме. Вместо этого корреляции откликов поддерживаются за счёт передачи информации от одной «измеренной» частицы к другой быстрее, чем произойдёт второе измерение.

Взято отсюда.


К сожалению, я не занимаюсь физикой ни профессионально ни даже на уровне любителя, на безошибочность не претендую. Главная цель статьи — продемонстрировать как сделать понятную для знакомых с программированием модель. Если кто-то профессионально работает в данной области, то вместо того, чтобы упрекать — попробуйте написать более точные модели взаимодействий по мотивам моей статьи.

Измерения


В каждой из моделей (и в детерминистической, и в суперпозиционной) будем проводить с запутанными частицами два эксперимента, соответствующие первому и второму условию по Мермину:

  1. Сначала установим оба датчика в одинаковую позицию. В этом случае будем получать 100% разные результаты (спины запутанных частиц зеркальны по всем трем осям).
  2. Затем будем устанавливать позицию датчиков случайным образом.


Вот код первого эксперимента:

var totalAttempts = 10000; // всего измерений
var disparityCount = 0; // сколько значений не совпало

for (int attemptNumber = 1; attemptNumber <= totalAttempts; attemptNumber++)
{
    var entanglementParticles = new EntanglementParticles(); // Зарождение пары запутанных частиц

    var position = GetRandomInteger(1, 3); // Выбираем позицию переключателя на датчике случайным образом

    // Первый и второй датчик устанавливаем в одну и ту же позицию
    int firstSensorPosition = position;
    int secondSensorPosition = position;

    bool firstValue = entanglementParticles.First.GetValue(firstSensorPosition); // Значение первой частицы с учетом позиции первого датчика
    bool secondValue = entanglementParticles.Second.GetValue(secondSensorPosition); // Значение второй частицы с учетом позиции второго датчика

    if (firstValue != secondValue) // подсчет количества не совпавших значений
        disparityCount++;
}

Console.WriteLine("Эксперимент №1: {0}% значений не совпало", (decimal)disparityCount / totalAttempts * 100); // все не совпали


Вот код второго эксперимента:

var totalAttempts = 10000; // всего измерений
var disparityCount = 0; // сколько значений не совпало

for (int attemptNumber = 1; attemptNumber <= totalAttempts; attemptNumber++)
{
    var entanglementParticles = new EntanglementParticles(); // Зарождение пары запутанных частиц

    int firstSensorPosition = GetRandomInteger(1, 3); // Случайным образом устанавливаем позицию датчика 1
    int secondSensorPosition = GetRandomInteger(1, 3); // Случайным образом устанавливаем позицию датчика 2

    bool firstValue = entanglementParticles.First.GetValue(firstSensorPosition); // Значение первой частицы с учетом позиции первого датчика
    bool secondValue = entanglementParticles.Second.GetValue(secondSensorPosition); // Значение второй частицы с учетом позиции второго датчика

    if (firstValue != secondValue) // подсчет количества не совпавших значений
        disparityCount++;
}

Console.WriteLine("Эксперимент №2: {0}% значений не совпало", (decimal)disparityCount / totalAttempts * 100);


Для всех моделей частиц будут одни и те же тесты, только код частиц будут отличаться для детерминистической и суперпозиционной моделей (об этом ниже).

Детерминистическая модель


Для желающих сразу запустить код, это можно сделать из браузера: dotnetfiddle.net/8K7ZUF

Итак, согласно объяснению Мермина, у нас есть квантовая частица с 3 параметрами:

// Элементарная частица (к примеру, фотон)
public class Particle
{
    private bool _measured = false;

    public bool A { get; private set; } // Проекция спина на ось X
    public bool B { get; private set; } // Проекция спина на ось Y
    public bool C { get; private set; } // Проекция спина на ось Z

    public Particle(bool a, bool b, bool c)
    {
        A = a;
        B = b;
        C = c;
    }

    // Получаем значение с учетом позиции переключателя на датчике (всего 3 позиции).
    public bool GetValue(int sensorPosition)
    {
        if (_measured)
            throw new InvalidOperationException("Измерить можно только один раз!");

        _measured = true;

        switch (sensorPosition)
        {
            case 1:
                return A;
            case 2:
                return B;
            case 3:
                return C;
            default:
                throw new ArgumentOutOfRangeException();
        }
    }
}


Поскольку модель детерминистическая — все параметры частицы инициализированы в момент ее создания, то есть прямо в конструкторе. Единственное условие — измерение разрешено только один раз!

Далее. Пара запутанных частиц:

// Пара запутанных частиц
public class EntanglementParticles
{
    public Particle First { get; private set; } // Первая частица
    public Particle Second { get; private set; } // Вторая частица

    // Создание пары запутанных частиц (пока верим в детерминизм, считаем что с каждая частица имеет установленное значение до измерения)
    public EntanglementParticles()
    {
        var a = GetRandomBoolean();
        var b = GetRandomBoolean();
        var c = GetRandomBoolean();

        First = new Particle(a, b, c); // устанавливаем случайные значения
        Second = new Particle(!a, !b, !c); // устанавливаем значения, противоположные первой частице
    }
}


Видно, что значения каждой из частиц устанавливаются в момент создания пары запутанных частиц, причем параметры второй частицы зеркально противоположны параметрам первой (без этого не сможем пройти первый тест). Мы используем случайные числа, но согласно модели, параметры зависят от факторов в момент запутывания (как результат рулетки зависит от ряда факторов в момент раскручивания).

Полный код примера:

Код C# детерминистической модели
using System;

public class Program
{
    private static readonly Random Random = new Random();

    // Элементарная частица (к примеру, фотон)
    public class Particle
    {
        private bool _measured = false;

        public bool A { get; private set; } // Проекция спина на ось X
        public bool B { get; private set; } // Проекция спина на ось Y
        public bool C { get; private set; } // Проекция спина на ось Z

        public Particle(bool a, bool b, bool c)
        {
            A = a;
            B = b;
            C = c;
        }

        // Получаем значение с учетом позиции переключателя на датчике (всего 3 позиции).
        public bool GetValue(int sensorPosition)
        {
            if (_measured)
                throw new InvalidOperationException("Измерить можно только один раз!");

            _measured = true;

            switch (sensorPosition)
            {
                case 1:
                    return A;
                case 2:
                    return B;
                case 3:
                    return C;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
    }

    // Пара запутанных частиц
    public class EntanglementParticles
    {
        public Particle First { get; private set; } // Первая частица
        public Particle Second { get; private set; } // Вторая частица
                
        // Создание пары запутанных частиц (пока верим в детерминизм, считаем что с каждая частица имеет установленное значение до измерения)
        public EntanglementParticles()
        {
            var a = GetRandomBoolean();
            var b = GetRandomBoolean();
            var c = GetRandomBoolean();

            First = new Particle(a, b, c); // устанавливаем случайные значения
            Second = new Particle(!a, !b, !c); // устанавливаем значения, противоположные первой частице
        }
    }


    public static void Main(string[] args)
    {
        Experiment1(); // Эксперимент 1 по Мермину
        Experiment2(); // Эксперимент 2 по Мермину
    }

    private static void Experiment1()
    {
        var totalAttempts = 10000; // всего измерений
        var disparityCount = 0; // сколько значений не совпало

        for (int attemptNumber = 1; attemptNumber <= totalAttempts; attemptNumber++)
        {
            var entanglementParticles = new EntanglementParticles(); // Зарождение пары запутанных частиц
                        
                        var position = GetRandomInteger(1, 3); // Выбираем позицию переключателя на датчике случайным образом

                        // Первый и второй датчик устанавливаем в одну и ту же позицию
            int firstSensorPosition = position;
            int secondSensorPosition = position;

            bool firstValue = entanglementParticles.First.GetValue(firstSensorPosition); // Значение первой частицы с учетом позиции первого датчика
            bool secondValue = entanglementParticles.Second.GetValue(secondSensorPosition); // Значение второй частицы с учетом позиции второго датчика

            if (firstValue != secondValue) // подсчет количества не совпавших значений
                disparityCount++;
        }

        Console.WriteLine("Эксперимент №1: {0}% значений не совпало", (decimal)disparityCount / totalAttempts * 100); // все не совпали
    }

    private static void Experiment2()
    {
        var totalAttempts = 10000; // всего измерений
        var disparityCount = 0; // сколько значений не совпало

        for (int attemptNumber = 1; attemptNumber <= totalAttempts; attemptNumber++)
        {
            var entanglementParticles = new EntanglementParticles(); // Зарождение пары запутанных частиц

            int firstSensorPosition = GetRandomInteger(1, 3); // Случайным образом устанавливаем позицию датчика 1
            int secondSensorPosition = GetRandomInteger(1, 3); // Случайным образом устанавливаем позицию датчика 2

            bool firstValue = entanglementParticles.First.GetValue(firstSensorPosition); // Значение первой частицы с учетом позиции первого датчика
            bool secondValue = entanglementParticles.Second.GetValue(secondSensorPosition); // Значение второй частицы с учетом позиции второго датчика

            if (firstValue != secondValue) // подсчет количества не совпавших значений
                disparityCount++;
        }

        Console.WriteLine("Эксперимент №2: {0}% значений не совпало", (decimal)disparityCount / totalAttempts * 100);
    }

        
        // Вспомогательные функции

    private static bool GetRandomBoolean()
    {
        return GetRandomInteger(0, 1) == 1;
    }


    private static int GetRandomInteger(int from, int to)
    {
        return Random.Next(from, to + 1); // нам удобнее указывать с какого числа по какое включительно
    }
}



Запустить можно из браузера (еще раз ссылка: dotnetfiddle.net/8K7ZUF).

После запуска вот такие результаты:

Эксперимент №1: 100% значений не совпало
Эксперимент №2: 66.6300% значений не совпало


Первый тест пройден, соответствует происходящему в реальности. А вот второй — не соответствует, так как должны получить 50%!

В результате физики были вынуждены прийти к тому, что теория скрытых параметров ошибочна. А вместе с ней опровергнут принцип локальности и даже пошатнулся принцип причинности.

Суперпозиционная модель


Сразу ссылка на код примера, для любящих конкретику (можно запустить в браузере): dotnetfiddle.net/vop3nf

Чтобы объяснить полученные в ходе экспериментов результаты, пришлось использовать более сложные модели. В современных моделях состояние параметров частицы до измерения не определено, а сами запутанные частицы имеют возможность мгновенно (сверх скорости света) влиять на состояние друг друга. Вот как теперь выглядит наша модель элементарной частицы:

// Элементарная частица (к примеру, фотон)
public class Particle
{
    private Particle _superluminalChannel; // Организация связи с второй запутанной частицей по сверхсветовому каналу.
    private int? _measuredPosition;

    public bool? A { get; private set; } // Проекция спина на ось X
    public bool? B { get; private set; } // Проекция спина на ось Y
    public bool? C { get; private set; } // Проекция спина на ось Z

    internal void CreateSuperluminalChannelWith(Particle particle)
    {
        _superluminalChannel = particle;
    }

    // Получаем значение с учетом позиции переключателя на датчике (всего 3 позиции).
    public bool GetValue(int sensorPosition)
    {
        if (null != _measuredPosition)
            throw new InvalidOperationException("Измерить можно только один раз!");

        _measuredPosition = sensorPosition;

        if (null != _superluminalChannel._measuredPosition) // если другая запутанная частица уже была измеряна
        {
            var measuredValue = _superluminalChannel.GetNakedValue();

            // Если измеряли тот же параметр у другой частицы (позиция переключателя на датчиках совпала), то возвращаем значение, противоположное значению уже измерянной частицы.
            if (sensorPosition == _superluminalChannel._measuredPosition)
                return !measuredValue;

            if (GetRandomInteger(1, 4) == 1)
                return !measuredValue;

            return measuredValue;
        }

        // Установка значения. Происходит в момент измерения с нарушением принципа причинности, никакие причины на значение не влияли - чистый рандом.
        // Детерминизм терпит крах!
        var value = GetRandomBoolean();

        SetValue(sensorPosition, value);

        return value;
    }

    private bool GetNakedValue() // Запутанная частица получает значение частицы по сверхсветовому каналу уже после того, как было произведено измерение.
    {
        if (null == _measuredPosition)
            throw new InvalidOperationException();

        switch (_measuredPosition.Value)
        {
            case 1:
                return A.Value;
            case 2:
                return B.Value;
            case 3:
                return C.Value;
            default:
                throw new InvalidOperationException();
        }
    }

    private void SetValue(int position, bool value)
    {
        switch (position)
        {
            case 1:
                A = value;
                break;
            case 2:
                B = value;
                break;
            case 3:
                C = value;
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }
    }
}


Во-первых, параметры стали Nullable (могут не иметь значения) и в конструкторе мы их не устанавливаем. Во-вторых, появился метод CreateSuperluminalChannelWith для установки сверхсветового канала между частицами, т.е. теперь одна частица может получить состояние другой мгновенно, не взирая на расстояние. Ну и, главное, теперь состояние частицы устанавливается лишь в момент измерения (вызов метода GetValue) и зависит от того, было ли произведено измерение другой, связанной с ней, частицы.

Внутренность метода GetValue — чистое предположение. Как внутри устроена частица — никто не знает, но мы знаем, что работает она именно так: 100% несовпадений в случае измерения одинакового параметра и 50% несовпадений при измерении параметров в случайном порядке.

В моей версии кода частица по сверхсветовому каналу проверяет произведено ли измерение запутанной с ней и действует так:

  1. Если измеренный параметр другой частицы тот же, что мы пытаемся замерять — выдает противоположное значение.
  2. Если параметр другой, то в ¼ случаев выдает противоположное значение, а в ¾ случаев выдает одинаковое значение (так как раз получим 50/50).


В случае, если измерение не производилось — частица использует истинный рандом для установки своего значения, то есть происходит нарушение причинно-следственной связи (значение не существовало до измерения и само измерение не определило его значение).

Кстати! Вы можете переписать эту функцию иным образом, но чтобы результаты тестов были такими же. Все равно никто не знает как устроена элементарная частица и как достигается 50% для второго теста.

Пара запутанных частиц стала проще, так как в момент запутывания никаких значений не устанавливается (значения еще не определены):

// Пара запутанных частиц
public class EntanglementParticles
{
    public Particle First { get; private set; } // Первая частица
    public Particle Second { get; private set; } // Вторая частица

    // Создание пары запутанных частиц (значения не установлены, находятся в суперпозиции)
    public EntanglementParticles()
    {
        First = new Particle(); // значения не установлены, находятся в суперпозиции
        Second = new Particle(); // значения не установлены, находятся в суперпозиции

        // Частицы имеют возможность общаться по сврехсветовому каналу связи
        First.CreateSuperluminalChannelWith(Second);
        Second.CreateSuperluminalChannelWith(First);
    }
}


Полный код примера:

Суперпозиционная модель на C#
using System;

public class Program
{
    private static readonly Random Random = new Random();

    // Элементарная частица (к примеру, фотон)
    public class Particle
    {
        private Particle _superluminalChannel; // Организация связи с второй запутанной частицей по сверхсветовому каналу.
        private int? _measuredPosition;

        public bool? A { get; private set; } // Проекция спина на ось X
        public bool? B { get; private set; } // Проекция спина на ось Y
        public bool? C { get; private set; } // Проекция спина на ось Z

        internal void CreateSuperluminalChannelWith(Particle particle)
        {
            _superluminalChannel = particle;
        }

        // Получаем значение с учетом позиции переключателя на датчике (всего 3 позиции).
        public bool GetValue(int sensorPosition)
        {
            if (null != _measuredPosition)
                throw new InvalidOperationException("Измерить можно только один раз!");

            _measuredPosition = sensorPosition;

            if (null != _superluminalChannel._measuredPosition) // если другая запутанная частица уже была измеряна
            {
                var measuredValue = _superluminalChannel.GetNakedValue();

                // Если измеряли тот же параметр у другой частицы (позиция переключателя на датчиках совпала), то возвращаем значение, противоположное значению уже измерянной частицы.
                if (sensorPosition == _superluminalChannel._measuredPosition)
                    return !measuredValue;

                if (GetRandomInteger(1, 4) == 1)
                    return !measuredValue;

                return measuredValue;
            }

            // Установка значения. Происходит в момент измерения с нарушением принципа причинности, никакие причины на значение не влияли - чистый рандом.
            // Детерминизм терпит крах!
            var value = GetRandomBoolean();

            SetValue(sensorPosition, value);

            return value;
        }

        private bool GetNakedValue() // Запутанная частица получает значение частицы по сверхсветовому каналу уже после того, как было произведено измерение.
        {
            if (null == _measuredPosition)
                throw new InvalidOperationException();

            switch (_measuredPosition.Value)
            {
                case 1:
                    return A.Value;
                case 2:
                    return B.Value;
                case 3:
                    return C.Value;
                default:
                    throw new InvalidOperationException();
            }
        }

        private void SetValue(int position, bool value)
        {
            switch (position)
            {
                case 1:
                    A = value;
                    break;
                case 2:
                    B = value;
                    break;
                case 3:
                    C = value;
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
    }

    // Пара запутанных частиц
    public class EntanglementParticles
    {
        public Particle First { get; private set; } // Первая частица
        public Particle Second { get; private set; } // Вторая частица

        // Создание пары запутанных частиц (значения не установлены, находятся в суперпозиции)
        public EntanglementParticles()
        {
            First = new Particle(); // значения не установлены, находятся в суперпозиции
            Second = new Particle(); // значения не установлены, находятся в суперпозиции

            // Частицы имеют возможность общаться по сврехсветовому каналу связи
            First.CreateSuperluminalChannelWith(Second);
            Second.CreateSuperluminalChannelWith(First);
        }
    }


    public static void Main(string[] args)
    {
        Experiment1();
        Experiment2();
    }

    private static void Experiment1()
    {
        var totalAttempts = 10000; // всего измерений
        var disparityCount = 0; // сколько значений не совпало

        for (int attemptNumber = 1; attemptNumber <= totalAttempts; attemptNumber++)
        {
            var entanglementParticles = new EntanglementParticles(); // Зарождение пары запутанных частиц

            var position = GetRandomInteger(1, 3); // Выбираем позицию переключателя на датчике случайным образом

            // Первый и второй датчик устанавливаем в одну и ту же позицию
            int firstSensorPosition = position;
            int secondSensorPosition = position;

            bool firstValue = entanglementParticles.First.GetValue(firstSensorPosition); // Значение первой частицы с учетом позиции первого датчика
            bool secondValue = entanglementParticles.Second.GetValue(secondSensorPosition); // Значение второй частицы с учетом позиции второго датчика

            if (firstValue != secondValue) // подсчет количества не совпавших значений
                disparityCount++;
        }

        Console.WriteLine("Эксперимент №1: {0}% значений не совпало", (decimal)disparityCount / totalAttempts * 100); // все не совпали
    }

    private static void Experiment2()
    {
        var totalAttempts = 10000; // всего измерений
        var disparityCount = 0; // сколько значений не совпало

        for (int attemptNumber = 1; attemptNumber <= totalAttempts; attemptNumber++)
        {
            var entanglementParticles = new EntanglementParticles(); // Зарождение пары запутанных частиц

            int firstSensorPosition = GetRandomInteger(1, 3); // Случайным образом устанавливаем позицию датчика 1
            int secondSensorPosition = GetRandomInteger(1, 3); // Случайным образом устанавливаем позицию датчика 2

            bool firstValue = entanglementParticles.First.GetValue(firstSensorPosition); // Значение первой частицы с учетом позиции первого датчика
            bool secondValue = entanglementParticles.Second.GetValue(secondSensorPosition); // Значение второй частицы с учетом позиции второго датчика

            if (firstValue != secondValue) // подсчет количества не совпавших значений
                disparityCount++;
        }

        Console.WriteLine("Эксперимент №2: {0}% значений не совпало", (decimal)disparityCount / totalAttempts * 100);
    }


    private static bool GetRandomBoolean()
    {
        return GetRandomInteger(0, 1) == 1;
    }


    private static int GetRandomInteger(int from, int to)
    {
        return Random.Next(from, to + 1); // нам удобнее указывать с какого числа по какое включительно
    }
}



Результаты:

Эксперимент №1: 100% значений не совпало
Эксперимент №2: 49.7700% значений не совпало


Запустить в браузере: dotnetfiddle.net/vop3nf

Есть ли альтернативные модели?


Наличие сверхсветового канала для внутренней коммуникации очень удручает. Удручает особенно то, что этот канал частицы могут использовать только для своих внутренних нужд. Любые попытки заюзать этот канал для передачи данных пресекаются no-communication theorem (иначе бы можно было сделать по-настоящему глобальный интернет без этих ваших кабелей, антенн, воздушных шаров и тысяч спутников).

Можно попробовать создать модели частиц без сверхсветового канала для внутренней коммуникации, just for fun. Я попробовал и вот что у меня получилось.

Возьмем за основу первую модель (детерминистическую) и доработаем создание пары запутанных частиц:

public EntanglementParticles()
{
    bool a;
    bool b;
    bool c;

    do
    {
        a = GetRandomBoolean();
        b = GetRandomBoolean();
        c = GetRandomBoolean();

    } while (a == b && b == c);

    First = new Particle(a, b, c); // устанавливаем случайные значения
    Second = new Particle(!a, !b, !c); // устанавливаем значения, противоположные первой частице
}


Мы исключили варианты, при которых проекция всех спинов по всем трем осям одинакова. Мало ли, вдруг природа этот случай по какой-либо причине не терпит (как, ага, как Аристотель считал, что «природа не терпит пустоты» (horror vacui)) :) Так как все 3 проекции спина измерить одновременно невозможно — вполне допустимая гипотеза. Только в таком случае получаем результаты:

Эксперимент №1: 100% значений не совпало
Эксперимент №2: 56.4900% значений не совпало


Немного не дотягивает до желаемых 50% во втором эксперименте, но зато не требует нарушения принципа локальности и всяких там ваших сверхсветовых каналов для внутренней коммуникации. Кстати, я не видел результатов реальных измерений, может там не ровно 50%? Если кто найдет результаты реальных измерений — сможет опровергнуть или подтвердить данную модель.

Ссылка для запуска в браузере: dotnetfiddle.net/Iy60AL

Полный код примера:

Одна из маргинальных моделей
using System;

public class Program
{
    private static readonly Random Random = new Random();

    // Элементарная частица (к примеру, фотон)
    public class Particle
    {
        private bool _measured = false;

        public bool A { get; private set; } // Проекция спина на ось X
        public bool B { get; private set; } // Проекция спина на ось Y
        public bool C { get; private set; } // Проекция спина на ось Z

        public Particle(bool a, bool b, bool c)
        {
            A = a;
            B = b;
            C = c;
        }

        // Получаем значение с учетом позиции переключателя на датчике (всего 3 позиции).
        public bool GetValue(int sensorPosition)
        {
            if (_measured)
                throw new InvalidOperationException("Измерить можно только один раз!");

            _measured = true;

            switch (sensorPosition)
            {
                case 1:
                    return A;
                case 2:
                    return B;
                case 3:
                    return C;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
    }

    // Пара запутанных частиц
    public class EntanglementParticles
    {
        public Particle First { get; private set; } // Первая частица
        public Particle Second { get; private set; } // Вторая частица
                
        // Создание пары запутанных частиц (пока верим в детерминизм, считаем что с каждая частица имеет установленное значение до измерения)
        public EntanglementParticles()
                {
                        bool a;
                        bool b;
                        bool c;
                
                        do
                        {
                                a = GetRandomBoolean();
                                b = GetRandomBoolean();
                                c = GetRandomBoolean();
                
                        } while (a == b && b == c);
                
                        First = new Particle(a, b, c); // устанавливаем случайные значения
                        Second = new Particle(!a, !b, !c); // устанавливаем значения, противоположные первой частице
                }
    }


    public static void Main(string[] args)
    {
        Experiment1(); // Эксперимент 1 по Мермину
        Experiment2(); // Эксперимент 2 по Мермину
    }

    private static void Experiment1()
    {
        var totalAttempts = 10000; // всего измерений
        var disparityCount = 0; // сколько значений не совпало

        for (int attemptNumber = 1; attemptNumber <= totalAttempts; attemptNumber++)
        {
            var entanglementParticles = new EntanglementParticles(); // Зарождение пары запутанных частиц
                        
                        var position = GetRandomInteger(1, 3); // Выбираем позицию переключателя на датчике случайным образом

                        // Первый и второй датчик устанавливаем в одну и ту же позицию
            int firstSensorPosition = position;
            int secondSensorPosition = position;

            bool firstValue = entanglementParticles.First.GetValue(firstSensorPosition); // Значение первой частицы с учетом позиции первого датчика
            bool secondValue = entanglementParticles.Second.GetValue(secondSensorPosition); // Значение второй частицы с учетом позиции второго датчика

            if (firstValue != secondValue) // подсчет количества не совпавших значений
                disparityCount++;
        }

        Console.WriteLine("Эксперимент №1: {0}% значений не совпало", (decimal)disparityCount / totalAttempts * 100); // все не совпали
    }

    private static void Experiment2()
    {
        var totalAttempts = 10000; // всего измерений
        var disparityCount = 0; // сколько значений не совпало

        for (int attemptNumber = 1; attemptNumber <= totalAttempts; attemptNumber++)
        {
            var entanglementParticles = new EntanglementParticles(); // Зарождение пары запутанных частиц

            int firstSensorPosition = GetRandomInteger(1, 3); // Случайным образом устанавливаем позицию датчика 1
            int secondSensorPosition = GetRandomInteger(1, 3); // Случайным образом устанавливаем позицию датчика 2

            bool firstValue = entanglementParticles.First.GetValue(firstSensorPosition); // Значение первой частицы с учетом позиции первого датчика
            bool secondValue = entanglementParticles.Second.GetValue(secondSensorPosition); // Значение второй частицы с учетом позиции второго датчика

            if (firstValue != secondValue) // подсчет количества не совпавших значений
                disparityCount++;
        }

        Console.WriteLine("Эксперимент №2: {0}% значений не совпало", (decimal)disparityCount / totalAttempts * 100);
    }

        
        // Вспомогательные функции

    private static bool GetRandomBoolean()
    {
        return GetRandomInteger(0, 1) == 1;
    }


    private static int GetRandomInteger(int from, int to)
    {
        return Random.Next(from, to + 1); // нам удобнее указывать с какого числа по какое включительно
    }
}



Выводы


Хотелось бы побольше доступных толкований, наподобие тех, что высказал Мермин. На основе этого толкования мне удалось создать наглядные модели существующих теорий и даже выдвинуть альтернативную модель и эти модели не аллегорические — их можно запустить и посмотреть как они работают.

К сожалению, не имею временных ресурсов для более глубокого познания квантовой физики и надеюсь что знающие смогут последовать моему примеру и привести более точные работающие модели.

© Habrahabr.ru