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

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

Квантовая механика, излагаемая в обычных учебниках, — это алгоритм предсказания показаний приборов, она ничего не говорит о процессах, о том, что происходит в реальности. Для такой квантовой механики расчёт заканчивается в тот момент, когда подсчитана волновая функция (она же квантовое состояние). Именно это мы и делали в прошлой статье. Но новые результаты в философии физики показывают, что волновая функция — это не реальность, а только средство для проведения расчётов. О том, что всё-таки происходит в квантомеханической реальности, я рассказываю в другой статье. Там был разобран простой эксперимент с интерференцией, где квантовая частица, в роли которой выступал фотон, может дойти до финального датчика одним из двух путей. Казалось бы, если частица идёт строго одним путём, наличие альтернативы никак не должно влиять на результат, но оказывается, что в реальности это не так. Но в той статье остался невыясненным вопрос: всё-таки учитывая тот факт, что фотон попадает строго в один из двух датчиков, может и путём в таком случае он идёт строго определённым? Можно ли это рассчитать?

Оказывается, можно. Но для этого надо прибегнуть не к “книжной” квантовой механике, а к какой-либо теории, рассказывающей, что происходит в реальности, то есть к тому что ещё называется интерпретацией квантовой механики.

Интерпретаций есть несколько. Какая из них верна мы, строго говоря, не знаем — это важно понимать. Но у меня есть фаворит. Когда я думаю о квантовой механике, я рассуждаю именно в терминах и понятиях этой интерпретации, даже если итогом будет что-то верное в любой интерпретации. Чему нас учит эта интерпретация? Она учит, что невозможно рассчитать как именно летит квантовая частица, потому что её полёт не полностью детерминирован законами физики. Но можно рассчитать вариант как она может лететь так, чтобы в итоге законы соблюдались. Именно этим мы и займёмся: расчётом как может лететь квантовая частица.

Для этого мы используем метод расчёта матриц перехода, который называется flow theory. А матрицы перехода позволят построить “траекторию” частицы.

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

Напомню схему эксперимента:

Простой эксперимент с интерференцией. Фотоны вылетают из источника S, проходят через первое полупрозрачное зеркало, отражаются от промежуточных зеркал L, R, попадают на второе полупрозрачное зеркало, и, наконец, в один из двух детекторов T, U.
Простой эксперимент с интерференцией. Фотоны вылетают из источника S, проходят через первое полупрозрачное зеркало, отражаются от промежуточных зеркал L, R, попадают на второе полупрозрачное зеркало, и, наконец, в один из двух детекторов T, U.

Исходными данными для расчёта служит начальное квантовое состояние \psi^{(0)} и набор унитарных матриц U^{(t)}, которые задают динамику квантового состояния:

\psi^{(t)} = U^{(t)} \psi^{(t-1)}.

Наше квантовое состояние очень простое — это две амплитуды:

\psi^{(t)} = \begin{pmatrix} C_1 \\ C_2 \end{pmatrix},

смысл которых зависит от номера шага t. На начальном шаге C_1 = 1, C_2 = 0, что означает, что частица летит из реального источника, расположенного слева, а не воображаемого справа. На следующем шаге C_1 — это амплитуда того, что частица идёт левым путём и C_2 — что правым. На третьем и последнем шаге C_1 — амплитуда попадания в T, а C_2 — в U.

Наша цель — превратить U^{(t)} и \psi^{(t)} в матрицы перехода \Gamma^{(t)} такие, что если на t-м шаге вероятность пребывания в состоянии 1 равна P^{(t)}_1, а в состоянии 2 — P^{(t)}_2, то

\begin{pmatrix} P^{(t)}_1 \\ P^{(t)}_2 \end{pmatrix} = \Gamma^{(t)} \begin{pmatrix} P^{(t-1)}_1 \\ P^{(t-1)}_2 \end{pmatrix}.

Как же их вычислить?

Согласно flow theory для этого надо рассчитать максимальный поток вот в таком направленном графе:

(На рёбрах написана их максимальная пропускная способность.) Тогда отношение потока в средних рёбрах (обозначенных |U^{(t)}_{\cdot\cdot}|) к соответствующим входным потокам (|\psi^{(t-1)}_{\cdot}|^2) и даст элементы матрицы \Gamma^{(t)}.

Для расчёта максимального потока применим алгоритм Эдмондса — Карпа. Это очень простой и в то же время хитрый алгоритм, Его идея в том, чтобы рассматривать каждое ребро графа как пару из прямого и обратного рёбер, причём пропускная способность обратного ребра равна нулю. Казалось бы, зачем нужно ребро с нулевой пропускной способностью? А дело в том, что когда мы задаём какой-нибудь поток через какое-либо ребро, через обратное ребро нужно пропускать поток такой же, но с обратным знаком — отрицательный поток. Поскольку отрицательный поток меньше нуля, формально всё хорошо: поток меньше пропускной способности. При этом обратное ребро “открывается”: теперь через него можно пропускать положительный поток, пока общая сумма не превышает нуль. По всё тому же правилу через прямое ребро при этом пропускается равный отрицательный поток, так что полный поток через него уменьшается. Такая хитрая схема позволяет автоматитчески перебалансировать потоки, “откатывая” принятые ранее неправильные решения.

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

Будем писать программу снизу вверх. Начнём с построения графа. Поскольку он у нас простой (между каждой парой узлов не больше одного ребра в одну сторону), его можно закодировать как двумерный квадратный массив, где строки и столбцы — узлы, а значения — пропускная способность. Размер получается один исток + один сток + количество входных узлов + количество выходных (конечно, количество выходных узлов у нас равно количеству входных, но здесь на это можно не завязываться).

function build_flow_graph(start, finish, through) result(graph)
  use, intrinsic :: iso_fortran_env, only: dp => real64
  real(dp), intent(in), dimension(:) :: start
  real(dp), intent(in), dimension(:) :: finish
  real(dp), intent(in), dimension(:, :) :: through
  real(dp), dimension(size(start) + size(finish) + 2, size(start) + size(finish) + 2) :: graph
  integer :: i
  integer :: j

  if (size(start) /= size(through, 2)) error stop "hidden_flow:build_flow_graph:arg"
  if (size(finish) /= size(through, 1)) error stop "hidden_flow_build_flow_graph:arg"

  graph = 0.0_dp
  do i = 1, size(start)
    graph(2 + i, 1) = start(i)
  end do
  do j = 1, size(finish)
    graph(2, 2 + size(start) + j) = finish(j)
  end do
  do i = 1, size(start)
    do j = 1, size(finish)
      graph(2 + size(start) + j, 2 + i) = through(j, i)
    end do
  end do
end function

Далее нам нужен поиск кратчайшего пути в этом графе. Скажу честно, это самое сложное место во всей программе и до конца я его и сам не понял.

function find_shortest_path(graph, flow) result(path)
  use, intrinsic :: iso_fortran_env, only: dp => real64
  real(dp), intent(in), dimension(:, :) :: graph
  real(dp), intent(in), dimension(:, :) :: flow
  integer, dimension(:), allocatable :: path

  <...>

  if (size(graph, 1) /= size(graph, 2)) error stop "hidden_flow:find_shortest_path:arg"
  if (size(flow, 1) /= size(flow, 2)) error stop "hidden_flow:find_shortest_path:arg"
  if (size(flow, 1) /= size(graph, 1)) error stop "hidden_flow:find_shortest_path:arg"
  if (size(graph, 1) < 2) error stop "hidden_flow:find_shortest_path:arg"

Массивы graph и flow устроены одинаково: первый это граф с пропускными способностями, который мы формировали выше, а второй содержит текущие потоки через рёбра. Полностью заполненные рёбра не принимают участие в формировании пути. Поскольку нам понадобится сравнивать числа с плавающей точкой, это нужно будет делать с некоторой точностью:

real(dp), parameter :: eps = 1.0e-10_dp

Главная идея алгоритма — использовать очередь (FIFO) узлов. Для очереди сделаем кольцевой буфер:

integer, dimension(size(graph, 1) + 1) :: queue
integer :: queue_head, queue_tail

Размер буфера такой, чтобы в него могли влезть при нужде все узлы графа, причём индекс хвоста (первой незаполненной ячейки) queue_tail не должен наехать на индекс начала (индекс первой заполненной ячейки) queue_head.

Также нужно запоминать посещённые узлы и то, в какой узел из какого мы пришли (это используется на финальном этапе, чтобы собрать путь):

logical, dimension(size(graph, 1)) :: visited
integer, dimension(size(graph, 1)) :: prev

Для сборки пути неизвестной длины нужны переаллокации, значит нужно запоминать сколько памяти выделено и сколько из неё использовано, также понадобится второй временный буфер:

integer :: temp_capacity
integer :: temp_len
integer, dimension(:), allocatable :: temp

Общий алгоритм такой: 1) инициализируем очередь истоком, 2) пока очередь не исчерпается, достаём из неё узел, проходим по всем рёбрам из него в ещё не посещённые узлы и добавляем их в очередь, 3) когда дошли до стока, кратчайший путь найден, 4) если очередь исчерпалась, то пути нет.

queue(1) = 1
queue_head = 1
queue_tail = 2
visited = .false.
visited(1) = .true.
prev(1) = 0
q: do
  if (queue_tail == queue_head) then
    allocate(path(0))
    exit q
  end if
  i = queue(queue_head)
  queue_head = mod(queue_head, size(graph, 1) + 1) + 1
  do j = 1, size(graph, 1)
    if (.not. visited(j)) then
      if (graph(j, i) - flow(j, i) > eps) then
        visited(j) = .true.
        prev(j) = i
        if (j == 2) then
          <...>
          exit q
        end if
        queue(queue_tail) = j
        queue_tail = mod(queue_tail, size(graph, 1) + 1) + 1
      end if
    end if
  end do
end do q

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

То, что между узлами i и j есть ребро, через которое можно пропустить поток, записывается как graph(j, i) - flow(j, i) > eps.

Осталось собрать путь, используя информацию из prev:

if (j == 2) then
  temp_capacity = 8
  allocate(path(temp_capacity))
  temp_len = 0
  k = j
  do
    temp_len = temp_len + 1
    if (temp_len > temp_capacity) then
      temp_capacity = 2 * temp_capacity
      allocate(temp(temp_capacity))
      temp(1:temp_len - 1) = path(1:temp_len - 1)
      call move_alloc(temp, path)
    end if
    path(temp_len) = k
    k = prev(k)
    if (k == 0) exit
  end do
  if ( temp_len < temp_capacity ) then
    allocate(temp(temp_len))
    temp(1:temp_len) = path(1:temp_len)
    call move_alloc(temp, path)
  end if
  exit q
end if

Здесь используется встроенная процедура move_alloc, которая передаёт владение выделенной памятью от первого аргумента второму.

Полностью поиск кратчайшего пути выглядит так:

function find_shortest_path(graph, flow) result(path)
  use, intrinsic :: iso_fortran_env, only: dp => real64
  real(dp), intent(in), dimension(:, :) :: graph
  real(dp), intent(in), dimension(:, :) :: flow
  integer, dimension(:), allocatable :: path
  real(dp), parameter :: eps = 1.0e-10_dp
  integer, dimension(size(graph, 1) + 1) :: queue
  integer :: queue_head, queue_tail
  logical, dimension(size(graph, 1)) :: visited
  integer, dimension(size(graph, 1)) :: prev
  integer :: i, j
  integer :: temp_capacity
  integer :: temp_len
  integer, dimension(:), allocatable :: temp
  integer :: k

  if (size(graph, 1) /= size(graph, 2)) error stop "hidden_flow:find_shortest_path:arg"
  if (size(flow, 1) /= size(flow, 2)) error stop "hidden_flow:find_shortest_path:arg"
  if (size(flow, 1) /= size(graph, 1)) error stop "hidden_flow:find_shortest_path:arg"
  if (size(graph, 1) < 2) error stop "hidden_flow:find_shortest_path:arg"

  queue(1) = 1
  queue_head = 1
  queue_tail = 2
  visited = .false.
  visited(1) = .true.
  prev(1) = 0
  q: do
    if (queue_tail == queue_head) then
      allocate(path(0))
      exit q
    end if
    i = queue(queue_head)
    queue_head = mod(queue_head, size(graph, 1) + 1) + 1
    do j = 1, size(graph, 1)
      if (.not. visited(j)) then
        if (graph(j, i) - flow(j, i) > eps) then
          visited(j) = .true.
          prev(j) = i
          if (j == 2) then
            temp_capacity = 8
            allocate(path(temp_capacity))
            temp_len = 0
            k = j
            do
              temp_len = temp_len + 1
              if (temp_len > temp_capacity) then
                temp_capacity = 2 * temp_capacity
                allocate(temp(temp_capacity))
                temp(1:temp_len - 1) = path(1:temp_len - 1)
                call move_alloc(temp, path)
              end if
              path(temp_len) = k
              k = prev(k)
              if (k == 0) exit
            end do
            if ( temp_len < temp_capacity ) then
              allocate(temp(temp_len))
              temp(1:temp_len) = path(1:temp_len)
              call move_alloc(temp, path)
            end if
            exit q
          end if
          queue(queue_tail) = j
          queue_tail = mod(queue_tail, size(graph, 1) + 1) + 1
        end if
      end if
    end do
  end do q
end function

Теперь нетрудно написать определение максимального потока методом Эдмондса — Карпа:

function edmonds_karp(graph) result(flow)
  use, intrinsic :: iso_fortran_env, only: dp => real64
  real(dp), intent(in), dimension(:, :) :: graph
  real(dp), dimension(size(graph, 1), size(graph, 1)) :: flow
  integer, dimension(:), allocatable :: path
  integer :: i
  real(dp) :: f

  if (size(graph, 1) /= size(graph, 2)) error stop "hidden_flow:edmonds_karp:arg"
  if (size(graph, 1) < 2) error stop "hidden_flow:edmonds_karp:arg"

  flow = 0.0_dp
  do
    path = find_shortest_path(graph, flow)
    if (size(path) < 2) exit
    f = graph(path(size(path) - 1), path(size(path))) - flow(path(size(path) - 1), path(size(path)))
    do i = size(path) - 2, 1, -1
      f = min(f, graph(path(i), path(i + 1)) - flow(path(i), path(i + 1)))
    end do
    do i = size(path) - 1, 1, -1
      flow(path(i), path(i + 1)) = flow(path(i), path(i + 1)) + f
      flow(path(i + 1), path(i)) = flow(path(i + 1), path(i)) - f
    end do
  end do
end function

Поскольку find_shortest_path возвращает путь в обратном порядке, мы и проходим его в обратном порядке (хотя можно было бы и в прямом: нам важно из каких рёбер состоит путь, а не в каком они порядке). Переменная f — это максимальный поток, который можно пропустить через найденный путь. Как и говорилось выше, мы прибавляем этот поток к потоку через прямое ребро и отнимаем от потока через обратное.

Теперь можно вычислить матрицы перехода:

function calc_step_matrix(psi, u) result(m)
  use, intrinsic :: iso_fortran_env, only: dp => real64
  complex(dp), intent(inout), dimension(:) :: psi
  complex(dp), intent(in), dimension(:, :) :: u
  real(dp), dimension(size(psi), size(psi)) :: m
  real(dp), dimension(size(psi)) :: start
  real(dp), dimension(size(psi)) :: finish
  real(dp), dimension(size(psi), size(psi)) :: through
  real(dp), dimension(size(psi) * 2 + 2, size(psi) * 2 + 2) :: graph
  real(dp), dimension(size(psi) * 2 + 2, size(psi) * 2 + 2) :: flow
  integer :: i, j
  real(dp), parameter :: eps = 1.0e-10_dp

  if (size(psi) /= size(u, 1)) error stop "hidden_flow:calc_step_matrix:arg"
  if (size(psi) /= size(u, 2)) error stop "hidden_flow:calc_step_matrix:arg"

  start = abs(psi) ** 2
  psi = matmul(u, psi)
  finish = abs(psi) ** 2
  through = abs(u)
  graph = build_flow_graph(start, finish, through)
  flow = edmonds_karp(graph)
  do i = 1, size(psi)
   do j = 1, size(psi)
     if (start(i) <= eps) then
       m(j, i) = 0.0_dp
     else
       m(j, i) = flow(2 + size(psi) + j, 2 + i) / start(i)
     end if
   end do
  end do
end function

Отдельно обработывается случай, если |\psi^{(t-1)}_i|^2 = 0: на ноль лучше лишний раз не делить. В таком случае частица не может оказаться в соответствующем состоянии, так что не столь важно как заполнить соответствующую колонку m (она же \Gamma^{(t)}), поэтому мы просто заполняем её нулями.

Теперь, вычислив матрицу переходов, можно найти траекторию. Она складывается из случайных переходов. На каждом шаге мы берём столбец, соответствующий текущему состоянию, и используем содержащиеся в нём вероятности переходов чтобы случайно выбрать следующее состояние:

function calc_steps(psi, u, conf) result(path)
  use, intrinsic :: iso_fortran_env, only: dp => real64, i8 => int8
  complex(dp), intent(inout), dimension(:) :: psi
  complex(dp), intent(in), dimension(:, :, :) :: u
  integer(i8), intent(in) :: conf
  integer(i8), dimension(size(u, 3) + 1) :: path
  real(dp), dimension(size(psi), size(psi)) :: m
  integer :: i
  integer(i8) :: j
  real(dp) :: p
  real(dp) :: q

  if (size(u, 1) /= size(psi)) error stop "hidden_flow:calc_steps:arg"
  if (size(u, 2) /= size(psi)) error stop "hidden_flow:calc_steps:arg"
    
  path(1) = conf
  do i = 1, size(u, 3)
    m = calc_step_matrix(psi, u(:, :, i))
    call random_number(p)
    path(i + 1) = size(psi) ! prevent round error strike
    q = 0.0_dp
    do j = 1, size(psi)
      q = q + m(j, path(i))
      if (q > p) then
        path(i + 1) = j
        exit
      end if
    end do
  end do
end function

Ну и давайте наконец посчитаем траекторию для нашего мысленного эксперимента. У нас будет всего два состояния (n = 2) и три момента времени (t = 3), то есть два шага. На первом шаге работает первое полупрозрачное зеркало, на втором второе. Зеркала одинаковые, поэтому u_1 и u_2 в коде заданы одинаковыми.

subroutine calc_path
  use, intrinsic :: iso_fortran_env, only: dp => real64, i8 => int8
  integer, parameter :: n = 2
  complex(dp), dimension(n), parameter :: psi_0 = [(1.0_dp, 0.0_dp), (0.0_dp, 0.0_dp)]
  real(dp), parameter :: one_over_sqrt_two = 1.0_dp / sqrt(2.0_dp)
  complex(dp), dimension(n, n), parameter :: u_1 = reshape([ &
    -one_over_sqrt_two, one_over_sqrt_two, &
    one_over_sqrt_two, one_over_sqrt_two &
  ], [n, n])
  complex(dp), dimension(n, n), parameter :: u_2 = reshape([ &
    -one_over_sqrt_two, one_over_sqrt_two, &
    one_over_sqrt_two, one_over_sqrt_two &
  ], [n, n])
  integer, parameter :: t = 3
  integer(i8), dimension(t) :: path
  complex(dp), dimension(n) :: psi
  complex(dp), dimension(n, n, t - 1) :: u

  u(:, :, 1) = u_1
  u(:, :, 2) = u_2
  psi = psi_0
  path = calc_steps(psi, u, 1_i8)
  print *, path
end subroutine

Запустим программу несколько раз и увидим то такой вывод:

    1    2    1

то такой:

    1    1    1

То есть частица идёт то левым путём, то правым, но в конце всегда оказывается в левом детекторе. Конечно, на самом деле именно это и ожидалось, но здорово, что всё сработало.

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

Комментарии (11)


  1. SergMCMLXXX
    25.10.2026 15:22

    Если посадить за стол человека, дать ему в руки карандаш и заставить написать 100 цифр, а потом посчитать с какой вероятность классический компьютер угадает написанное число, то можно сильно удивиться...

    пока вся эта квантовая эпопея именно так и выглядит.

    Зы. и строят центры якобы для ии, но на самом деле, для взлома эллиптической криптографии.


  1. rudnyi
    25.10.2026 15:22

    Такой вопрос. Давайте, возьмем классическую механику. Говорит ли классическая механика о том, что происходит в реальности?


    1. black_warlock_iv Автор
      25.10.2026 15:22

      Да. Например, ньютоновская механика говорит, что мир состоит из точечных частиц, каждая из которых имеет определённое положение в пространстве, и эти координаты меняются с течением времени.


      1. rudnyi
        25.10.2026 15:22

        Я не помню, показывал ли я вам цитату Вейля, но она имеет прямое отношение к вашему ответу:

        'Проблема, разрешить которую должна теория научного познания, может быть грубо сформулирована следующим образом. Комета отыщет своё завтрашнее положение, начав с положения сегодняшнего и осуществив своё движение в действительности. Мы ищем её завтрашнее положение, выписывая некие числа, которые символизируют данные, имеющиеся в данный момент в нашем распоряжении, производя с ними сложные символические операции и тем самым предсказывая будущее положение кометы, не ожидая действительного осуществления её движения. Что же общего имеет этот символьный процесс астронома с реальным процессом кометы?'

        Как бы вы ответили на этот вопрос Вейля?


        1. black_warlock_iv Автор
          25.10.2026 15:22

          Что процесс и не должен иметь ничего общего.

          На самом деле физики-теоретики (включаю сюда и астрономов) — зачастую этого не осознавая — работают не с актуальным миром и актуальной кометой, а с такой философской штукой, как “возможный мир”. Физиков, правда, интересуют в основном такие миры, где действуют известные нам по нашему миру законы физики или что-то похожее на них. (Философов интересует более широкий круг возможных миров.) Да, актуальная комета ещё не долетела. Может быть она вообще не долетит: мало ли какие в реальном космосе неучтённые астрономом случайные факторы. Но астроном работает не с ней, а с её двойником в возможном мире, созданным его пером, его мыслью, его расчётами.

          Познание же происходит за счёт того, что воображаемый мир немножко похож на актуальный. Поэтому шанс, что движение реальной кометы будет сильно близко к воображаемой, очень велик, хотя и не 100%.

          (Зачастую подразумеваемая цепочка возможных миров оказывается очень сложной. Сначала идёт мир, в котором законы такие же как в нашем, но другая актуальная ситуация. Затем цепочка прокидывается к миру, где законы не такие как в нашем мире, но такие, как в наших книгах по физике. Затем от мира с точными законами идёт переход в мир с законами приближёнными. Наконец, от мира с символьными законами делается прыжок в мир, где законы выражены соответствующей численной схемой. Для этого последнего мира делается расчёт, после чего итоговый факт переносится по цепочке миров обратно в актуальный мир. Если везёт, мы узнаём что-то важное о нашем мире в итоге.)


          1. rudnyi
            25.10.2026 15:22

            В данном случае непонятно, что такое законы в нашем мире, которые управляют движением планеты. Это классическая механика?


            1. black_warlock_iv Автор
              25.10.2026 15:22

              Нет, в нашем мире классическая механика неверна. Всем управляет квантовая механика. А может некая более глубокая, ещё не открытая теория. И вообще это неправильное слово – “управляет”. Никто движением планеты не управляет. Оно просто такое, что выполняются определённые законы. Фундаментальные законы – не законы управления, а законы факта: они просто делят факты на возможные и невозможные (или присваивают разную вероятность разным фактам, если законы вероятностные).


  1. MonteDegro
    25.10.2026 15:22

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


    1. black_warlock_iv Автор
      25.10.2026 15:22

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

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

      Кстати, это не класс интерпретаций. Это одна интерпретация, которая переосмысливает класс теорий со скрытыми параметрами и делает их все своей частью. Они в рамках этой интерпретации не конкурируют, а предоставляют альтернативы, как можно в симуляции, в расчёте обеспечить соблюдение необходимых законов, которые выполняются в реальности. В реальности эти законы выполняются просто потому что они законы и они не требуют конкретного способа чтобы они выполнялись. Но нам для расчётов нужен какой-то способ подгонки под эти законы и любая подходящая теория годится как инструмент для этой цели. Я выбрал flow theory, но это не принципиально. Если бы я работал с непрерывным временем и пространством, я мог бы выбрать, например, бомовскую механику.


  1. misha_erementchouk
    25.10.2026 15:22

    Наша цель — превратить U^{(t)} и \psi^{(t)} в матрицы перехода \Gamma^{(t)} такие, что если на t-м шаге вероятность пребывания в состоянии равна P^{(t)}_1, а в состоянии 2 — P^{(t)}_2, то

    \begin{pmatrix} P^{(t)}_1 \\ P^{(t)}_2 \end{pmatrix} = \Gamma^{(t)} \begin{pmatrix} P^{(t-1)}_1 \\ P^{(t-1)}_2 \end{pmatrix}.

    Такие матрицы перехода должны зависеть от самого состояния \psi^{(t-1)}. Элементарный пример, пусть

    U = \frac{1}{\sqrt{2}} \begin{pmatrix} 1 & 1 \\ 1 & -1 \end{pmatrix}

    Далее, пусть \psi^{(t-1)} = (1, 1)^T/\sqrt{2}, т.е. P_1^{(t-1)} = P_2^{(t-1)} = 1/2. Тогда P_1^{(t)} = 1 и P_2^{(t)} = 0.

    Пусть теперь \psi^{(t-1)} = (1, -1)^T/\sqrt{2}, т.е. все еще P_1^{(t-1)} = P_2^{(t-1)} = 1/2, но теперь P_1^{(t)} = 0 и P_2^{(t)} = 1.

    Никакая матрица \Gamma^{(t)}, независящая от \psi^{(t-1)}, такой ответ не даст.

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


    1. black_warlock_iv Автор
      25.10.2026 15:22

      Такие матрицы перехода должны зависеть от самого состояния \psi^{(t-1)}.

      Совершенно верно. Есть теорема, что они не могут от него не зависеть. И в этом есть глубокий физический смысл: если бы матрицы перехода не зависели от волновой функции, это бы значило, что нам удалось построить марковскую стохастическую модель квантовой механики. Но доказано, что квантовая механика, действительно, эквивалентна стохастической модели, но модели немарковской. А волновая функция является латентной переменной эквивалентной скрытой марковской модели. Поэтому либо вероятности переходов должны зависеть от истории, причём на очень большую неограниченную глубину (фактически от начального состояния). Либо эквивалентно они должны зависеть от волновой функции.