Uma classe para vectores #ifndef __SIMPLEARRAY__ #define __SIMPLEARRAY__ #include <iostream> using namespace std; template<class T> class SimpleArray { template<class U> friend ostream &operator <<(ostream&, const SimpleArray<U>&); public: SimpleArray(int n); // Create array of n elements SimpleArray(); // Create array of 0 elements SimpleArray(const SimpleArray<T>&); // Copy array ~SimpleArray(); // Destroy array T& operator[](int i); // Subscripting int numElts(); // Number of elements SimpleArray<T>& operator=(const SimpleArray<T>&); // Array assignment SimpleArray<T>& operator=(T); // Scalar assignment void setSize(int n); // Change size private: int num_elts; // Number of elements T* ptr_to_data; // Pointer to built-in array of elements void copy(const SimpleArray<T>& a); // Copy in elements of a }; #endif Curso C++ (J. Seixas) Overloading de operadores Primeiro: nem todos os operadores são passíveis de overloading. Operadores que podem ser overloaded + - * / = < > += -= *= /= << >> <<= >>= == != <= >= ++ -% & ^ ! | ~ &= ^= |= && || %= [] () , ->* -> new delete new[] delete[] Operadores que não podem ser overloaded :: .* . ?: Segundo: não é possível alterar nem a precedência, nem a associatividade dos operadores. Terceiro: Os operadores iniciais ficam inacessíveis! Não há garantia quanto à ordem segundo a qual os operandos são avaliados. Quarto: O significado dos operadores para os tipos pré-definidos não pode ser alterado. Não alterar operadores como , &, && ou || Curso C++ (J. Seixas) Uma classe para vectores Overloading do operador []: template<class T> SimpleArray<T>::~SimpleArray() { delete [] ptr_to_data; } template<class T> T& SimpleArray<T>::operator[](int i) { return ptr_to_data[i]; } template<class T> int SimpleArray<T>::numElts() { return num_elts; } Curso C++ (J. Seixas) Uma classe para vectores Overloading do operador =: (assignment) template<class T> SimpleArray<T>& SimpleArray<T>::operator=(const SimpleArray<T>& rhs) { if ( ptr_to_data != rhs.ptr_to_data ) { setSize( rhs.num_elts ); copy(rhs); } return *this; } Os operadores = retornam uma referência: não é necessário criar e destruir uma cópia temporária do resultado. Como retornam uma referência ao objecto da esquerda permitem pôr a=b=c; Curso C++ (J. Seixas) Uma classe para vectores Overloading do operador <<: (assignment) template<class T> ostream &operator <<(ostream& stream, const SimpleArray<T>& v){ for(int i=0; i < v.num_elts ;++i) stream << v.ptr_to_data[i] << " "; return stream; } Os operadores << retornam uma referência a ostream e assim podemos por cout << v << u << endl; Curso C++ (J. Seixas) Uma classe para vectores Uma função com o qualificativo friend, seja ela membro de outra classe ou global, pode aceder a membros não públicos da classe que a classificou como friend. A classificação de friend a uma dada função só se aplica a essa função, não a todas com o mesmo nome! Se se declarar uma classe como friend todas as suas funções serão friend. A posição onde a declaração de friend está na definição da classe é irrelevante. Os especificadores de acesso private e public não têm qualquer efeito em friend. Curso C++ (J. Seixas) Uma classe para vectores Implementação (I): template<class T> SimpleArray<T>::SimpleArray(int n) { num_elts = n; ptr_to_data = new T[n]; } template<class T> SimpleArray<T>::SimpleArray() { num_elts = 0; ptr_to_data = 0; } template<class T> SimpleArray<T>::SimpleArray(const SimpleArray<T>& a) { num_elts = a.num_elts; ptr_to_data = new T[num_elts]; copy(a); // Copy a's elements } template<class T> void SimpleArray<T>::copy(const SimpleArray<T>& a) { // Copy a's elements into the elements of *this T* p = ptr_to_data + num_elts; T* q = a.ptr_to_data + num_elts; while (p > ptr_to_data) *--p = *--q; } Curso C++ (J. Seixas) Uma classe para vectores Implementação (II): template<class T> SimpleArray<T>::~SimpleArray() { delete [] ptr_to_data; } template<class T> T& SimpleArray<T>::operator[](int i) { return ptr_to_data[i]; } template<class T> int SimpleArray<T>::numElts() { return num_elts; } Curso C++ (J. Seixas) Uma classe para vectores Implementação (III): template<class T> SimpleArray<T>& SimpleArray<T>::operator=(const SimpleArray<T>& rhs) { if ( ptr_to_data != rhs.ptr_to_data ) { setSize( rhs.num_elts ); copy(rhs); } return *this; } template<class T> void SimpleArray<T>::setSize(int n) { if (n != num_elts) { delete [] ptr_to_data; num_elts = n; // Delete old elements, // set new count, ptr_to_data = new T[n]; // and allocate new elements } } Curso C++ (J. Seixas) Uma classe para vectores Implementação (IV): template<class T> SimpleArray<T>& SimpleArray<T>::operator=(T rhs) { T* p = ptr_to_data + num_elts; while (p > ptr_to_data) *--p = rhs; return *this; } Curso C++ (J. Seixas) Exemplo: O modelo de Ising O modelo de Ising (estudado inicialmente pelo físico Ernst Ising por sugestão do seu orientador de doutoramento Wilhelm Lenz) é um modelo matemático em Física Estatística, muito importante para estudar fenómenos como o ferromagnetismo. Teve e tem um papel fundamental na moderna teoria das transições de fase e fenómenos críticos. Curso C++ (J. Seixas) Exemplo: O modelo de Ising O modelo mais simples consiste numa cadeia de “spins” Si cada um só podendo tomar os valores ±1. A energia do sistema para uma dada configuração de spins é dada por Cada configuração de spins é uma “fotografia” do sistema num dado instante Curso C++ (J. Seixas) Exemplo: O modelo de Ising O objectivo da Física Estatística é determinar o valor das grandezas termodinâmicas macroscópicas a partir da dinâmica microscópica do sistema. A energia do sistema em cada instante é dada pela expressão anterior. A energia média ao longo do tempo é dada por 1 Nconf E En Nconf n1 Curso C++ (J. Seixas) Exemplo: O modelo de Ising Calcular <E> para todas as possíveis configurações é possível, mas: Será que todas as configurações têm a mesma importância no processo? Será que no intervalo de tempo (mesmo longo) em que estamos a observar todas elas aparecem? Se não, como determinar <E> tendo em vista a distribuição de configurações mais frequentes? Como determinar a frequência com que as configurações aparecem? … O objectivo da Física Estatística é dar respostas a estas perguntas Curso C++ (J. Seixas) Exemplo: O modelo de Ising 1ª pergunta: Como calcular a frequência (probabilidade) com que aparece uma dada configuração? Resposta (1ª parte): Há muitas configurações que têm a mesma energia associada sobretudo se há simetrias no sistema. Exemplo (modelo de Ising ferromagnético): Ns E J sisi1 i1 Existe uma simetria Z2: trocar s→-s fornece o mesmo resultado para E. Existem configurações com energia menor do que outras. Em física temos sempre de tender para um mínimo de energia. Curso C++ (J. Seixas) Exemplo: O modelo de Ising 1ª pergunta: Como calcular a frequência (probabilidade) com que aparece uma dada configuração? Resposta (2ª parte): Configurações todos os spins para baixo excepto 1: N; Configurações todos os spins para baixo excepto 2: N(N-1); desordenado N(N-1)/2! Configurações todos os spins para baixo excepto k: N!/(N-k)!; desordenado N!/k!(N-k)! Curso C++ (J. Seixas) Exemplo: O modelo de Ising 1ª pergunta: Como calcular a frequência (probabilidade) com que aparece uma dada configuração? Resposta (2ª parte): A probabilidade de ter N spins e colocá-los N1 na caixa 1, N2 na caixa 2, … Nk na caixa k é k 1 N! (N N1 )! Nk ! ... N! W i1 Ni! N1 (N N1 )! N2 (N N1 N2 )! Nk !0! Se houver degenerescência, o número de maneiras de preencher uma caixa i é gi então a expressão anterior é gNii W N! i1 Ni! k Curso C++ (J. Seixas) Exemplo: O modelo de Ising 1ª pergunta: Como calcular a frequência (probabilidade) com que aparece uma dada configuração? Resposta (3ª parte): Qual é o valor máximo da probabilidade, ou seja, qual o conjunto {Ni} para os quais W é máxima? Na realidade, essa é a configuração mais provável, ou seja, a que aparecerá mais vezes. Resposta: Usar multiplicadores de Lagrange minimizando f (Ni ) ln(W) (N Ni ) (E Nii ) Curso C++ (J. Seixas) Exemplo: O modelo de Ising 1ª pergunta: Como calcular a frequência (probabilidade) com que aparece uma dada configuração? Resposta (3ª parte): Usando a aproximação de Stirling NN N! 2N N e e pondo igual a 0 a derivada em ordem a Ni temos Ni Curso C++ (J. Seixas) gi e i gi e( i ) / kT Exemplo: O modelo de Ising 1ª pergunta: Como calcular a frequência (probabilidade) com que aparece uma dada configuração? Resposta (3ª parte): Função de partição: N Ni Função de partição e logo giei / kT Ni N ; Z giei / kT Z i Curso C++ (J. Seixas) Exemplo: O modelo de Ising 2ª pergunta: O comportamento do sistema não é portanto possível de seguir em detalhe analiticamente. Se as configurações não são todas equiprováveis, como escolher as melhores de forma a não perder tempo com as que são mais improváveis? Resposta (entre outras): Algoritmo de Metropolis Curso C++ (J. Seixas)