Números Aleatórios

De Física Computacional
Revisão de 15h49min de 31 de março de 2022 por Jhordan (discussão | contribs)
Ir para navegação Ir para pesquisar

Processos Aleatórios

Introdução

Existem na natureza processos de caráter estocástico, cujo resultado não pode ser predito a priori. Os exemplos típicos são o lançamento de uma moeda, o jogo dos dados ou a roleta. Em cada um desses casos sabemos quais são os resultados possíveis, porem não ha como predizer o resultado da próxima jogada. Entretanto podemos sim dizer qual será resultado em termos estatísticos de um grande número de jogadas: se lançarmos 1000 vezes uma moeda aproximadamente 50% das vezes o resultado será cara, e a percentagem será cada vez mais próxima de 50% quanto maior o número de lançamentos. O mesmo pode ser dito da roleta: num grande número de jogadas aproximadamente 1/37 das vezes terá dado o 17 por exemplo. Embora não seja suficiente para ganhar no jogo é um resultado previsível do ponto de vista estatístico. De uma outra forma, se nos fosse permitido colocar uma ficha nos pares e no zero ao mesmo tempo repetindo a jogada um grande número de vezes, teríamos lucro no final das contas.

Por outra parte existem na física processos cuja natureza é em principio determinística, cujo resultado é, em princípio, previsível conhecendo as condições inicias, mas que na prática resulta impossível como por exemplo a exata trajetória das moléculas de um gás.

Mesmo assim poderíamos integrar as equações de Newton de N partículas (moléculas ou planetas) com um dos algoritmos estáveis usados na unidade anterior: o Euler-Cromer ou de preferência o Verlet. O principio é o mesmo que no caso de uma única partícula como foi o caso do oscilador harmônico unidimensional. No caso de N partículas existem algumas complicações adicionais pois é necessário somar a força que as N-1 partículas fazem em uma dada partícula. À integração numérica das equações de movimento de N partículas é dada o nome de Dinâmica Molecular. O método é muito usado é viável num PC até 100000 ou 1 milhão de partículas. Porem depois de um determinado tempo a trajetória obtida para uma dada partícula pode estar muito afastada da trajetória teórica. No fundo acontece algo parecido com o problema da moeda. Ele é em princípio um problema determinístico mas na prática resulta randômico. Se diz que são problema sensíveis as condições iniciais: uma pequena variação na posição ou velocidade inicial da moeda se traduz numa trajetória muito diferente depois de um certo tempo.

Mas no caso de um gás, no fim não interessa pois nada importa a posição exata de uma dada molécula, o que importa são as propriedades estatísticas do sistema com um todo. Fazendo o análogo com o problema da moeda, é saber que proporção de cara ou coroa teremos depois de N lançamentos. No gás as medidas que interessam são a pressão, energia, temperatura, etc, propriedades médias do sistema em equilíbrio.

Dependendo das propriedades de interesse e dada essa caraterística randômica do movimento individual complexo de uma molécula qualquer, podemos adotar um modelo mais simples para simular o comportamento do sistema que o método de Dinâmica Molecular, relativamente difícil de programar. Tomemos o exemplo de um gás que está inicialmente contido numa metade de uma caixa, que está dividida ao meio por uma parede com um fim pequeno furo pelo qual pode passar uma molécula por vez. Sabemos que depois de um tempo o sistema alcançará o equilíbrio e que o número médio de partículas em cada metade da caixa será N/2.

Uma maneira simples de simular esse processo e supor que as partículas não interagem entre elas e que a probabilidade (por unidade de tempo) de uma dada partícula trocar de lado e a mesma para todas independente do lado da caixa na qual se encontre. Podemos implementar esse modelo escolhendo aleatoriamente uma partícula e trocá-la de lado. Acompanhando este processo no tempo deveríamos observar a evolução do sistema ao equilíbrio.

Números aleatórios

Para implementar esse modelo precisamos números aleatórios. Os verdadeiros números aleatórios são aqueles que resultam de um experimento estocástico, como os exemplos citados ao começo: moeda, dados, roleta. Mas para poder usar em cálculos no computador devemos achar um método mais rápido de gerar um seqüência de números aleatórios, deve ser o própio computador quem forneça essa seqüência. Isso é possível como veremos em seguida, porem eles não são estritamente aleatórios, eles parecem não obedecer a nenhum padrão, nenhuma seqüência lógica parece estar por trás desses números, mas na verdade se trata de uma seqüência completamente previsível, só para quem conhece a regra de geração da seqüência, ou seja ninguém poderia acertar o próximo número a menos que conheça a receita. Ou seja, que podem se comportar como números aleatórios tão bons quanto os verdadeiros. Por isso são as vezes chamados de pseudo-aleatórios.

Uma maneira de gerar uma seqüência assim é por meio da operação de congruência (resto da divisão inteira):

xn+1 = resto { (a xn + b)/m }

onde a, b, m e os xn são todos números inteiros. Dependendo da escolha dos inteiros a, b e m, a sequencia de números {x1, x2, ..., xn} é uma sequencia randómica dos números entre 1 e m. A melhor maneira de entender como isso funciona é com um exemplo: Seja a=4, b=3 e m=1, e seja o x inicial x0= 2

Em python, o método da congruência pode ser implementado da seguinte forma:

# gerador de num aleatorios de congruencia
def randi():
    global x
    a = 1029; b= 221591; m = 1048576
    x = (a*x + b) % m
    return x

# entrar aqui um interiro como semente inicial
x = int(input('semente (entrar inteiro)? '))
for i in range(10):
    n = randi()
    print(i,n)

Como uma solução nativa em Python temos a biblioteca random, para obter um número aleatório entre 0 e 1 podemos utilizar random(), ou randint(a,b) para inteiros entre (incluindo) a e b:

import random
print("Número aleatório: ",random.random()) # Frações no conjunto [0,1)
print("Roleta:",random.randint(0,37))       # Inteiros no conjunto [0,37]
print("Dado:",int(random.random()*6)+1)     # Inteiros no conjunto [1,6]
print("Moeda: ", 2*random.randint(0,1)-1)   # Inteiros no conjunto {-1,1}

O caminhante aleatório, pode ser facilmente implementado, tanto para se ter a mesma probabilidade de se mover em qualquer direção quanto para probabilidades diferentes.

import random
import matplotlib.pyplot as plt

n = 100 #Número de passos
p =0.5    #probabilidade de ir para o lado direito
m = 10000     #Número de repetições
t =[]     #Lista para guardar todos os resultados
for i in range(m):     #Vamos repetir m vezes
  x=[0]                #Posição inicial
  for j in range(n):   #Com n passos em cada repetição
    dx = (+1) if (random.random()<=p) else (-1)
    x.append(x[j]+dx)  #Atualizamos a posição
  t.append(x)          #Salvamos o resultado final
med =[]                #Lista para guarar as medias

#Calcular a posição média em cada instante sobre as m repetições
for i in range(n):     #Vamos calcular os n passos
  c=0                  #Variável auxiliar
  for j in range(m):   #Sobre as m execuações
    c+=t[j][i]         #Pegamos o passo n da simulação m
  med.append(c/m)      #Dividimos pela quantidade de simulações
plt.plot(med)          #lembrando que a particula poderia ir até n passos

#Podemos ver também qual a % das vezes que a partícula j se moveu pra direita:
j=0 #Qual repetição
m = [ t[j][i]-t[j][i-1] for i in range(1,n)] #+1 -> direita, -1 -> esquerda
c=0 #Contador
for i in m:
  c = (c+1) if (i>0) else (c) #Somamos todas as vezes que se moveu para a direita
print("A particula {:d} se moveu para a direita {:.2f}% das vezes".format(j,100*c/len(m)))

A continução temos um exemplo de código FORTRAN implementando a simulação do exemplo do gas na caixa. No exemplo simulamos 1000 partículas e fica como exercício decidir que variáveis imprimir e como calculá-las. Também se é necessário imprimir a cada passo da simulação.

!Aula5: Programa Gas, simulação com 1000 partículas
Program Gas
Implicit None
Real*8 Randi
Integer N, i, j, t, x
Parameter (N = 1000)
Integer Box(N)

Read(*,*) t, x  !t:tempo de simulação, x:semente de Randi

Do i = 1, N
   Box(i) = -1
End Do

Do j = 1, t
   i = N*Randi(x)+1
   Box(i) = -Box(i)
   Print*, j, 'deixo/vc(exercício 2)'
End Do

End Program Gas

Observações sobre FORTRAN:

  1. Parameter é para assignar (em tempo de compilação) um valor fixo a uma variável que não pode mudar durante a execução do programa, evitando o erro decorrente de uma alteração involuntária por distração, etc.
  2. O segundo novo elemento é o vector A(10) ou B(5,20).
     No caso que nos ocupa é Box(N); a utilidade dele fica evidente no própio programa: de uma vez só definimos uma variável a qual, por meio do indice, permite guardar o estado de um grande número de variáveis. Neste caso são as posições das 1000 partículas.

Exercícios:

  1. Graficar a evolução temporal das partículas a esquerda e a direita da parede (ver figura acima).
  2. Observe o "tempo" necessário para entrar em regime estacionário. Como varia esse tempo se mudarmos o número de partículas. Você pode estabelecer uma relação entre t e N?
  3. Implemente uma maneira de calcular a média de partículas num lado da caixa (precissa os dois?) e veja como varia no tempo.
  4. Depende do intervalo usado para calcular a média?
  5. Observe a variação no número de partículas no regime estacionário. Implemente uma forma de quantificar essa variação no seu programa. Ou seja a desvio cuadrático médio ou flutuação
  6. Quantifique a dependencia do desvio no regime estacionário com o número de partículas