//Create a spin lattice of given width, height, exchange coupling and external field
        public IsingLattice(int p_width,
		                     int p_height,
		                     double p_ExchangeCoupling = 1,
		                     double p_ThermalEnergy = 0,
		                     double p_ExternalField = 0,
		                     int p_StabilityLimit = 1)
        {
            last_spins = new PeriodicSpinLattice (p_width, p_height);
            current_spins = new PeriodicSpinLattice (p_width, p_height);
            exchange_coupling = p_ExchangeCoupling;
            external_field = p_ExternalField;
            thermal_energy = p_ThermalEnergy;
            StabilityLimit = p_StabilityLimit;
            random_generator = new Random ();
            this.Randomize();
        }
 //Compute the probability of getting an up spin at a given position in a future state
 //that is given by Exp(-energy_up/ThermalEnergy)/(Exp(-energy_down/ThermalEnergy) + Exp(-energy_up/ThermalEnergy))
 //where energy_down = -energy_up
 double ComputeUpSpinProbability(PeriodicSpinLattice current_lattice, int h_pos, int v_pos)
 {
     if (ThermalEnergy != 0) {
         return 1 / (1 + Math.Exp (2 * ComputeEnergyPerSpin (current_lattice, h_pos, v_pos) / ThermalEnergy));
     } else {
         return (ComputeEnergyPerSpin (current_lattice, h_pos, v_pos) > 0) ? (0) : (1);
     }
 }
 //Compute the next spin state at a given position of the lattice, in a probabilistic fashion
 int ComputeFutureState(PeriodicSpinLattice current_lattice, int h_pos, int v_pos)
 {
     if (random_generator.NextDouble () < ComputeUpSpinProbability (current_lattice, h_pos, v_pos)) {
         return +1;
     } else {
         return -1;
     }
 }
        //Returns the energy per spin at a given position of the lattice: if multiplied by +1, gives
        //the energy associated to spin state +1, and if multiplied by -1, gives the energy associated
        //to spin state -1
        double ComputeEnergyPerSpin(PeriodicSpinLattice current_lattice, int h_pos, int v_pos)
        {
            //Measure nearest neighbour spins with periodic boundary conditions
            int left_spin = current_lattice [h_pos - 1, v_pos];
            int right_spin = current_lattice [h_pos + 1, v_pos];
            int top_spin = current_lattice [h_pos, v_pos - 1];
            int bottom_spin = current_lattice [h_pos, v_pos + 1];

            //Return the energy per spin associated to the requested spin state
            return -ExchangeCoupling * (left_spin + right_spin + top_spin + bottom_spin) - ExternalField;
        }
        //Copy the contents of one spin lattice into another spin lattice
        public bool CopyFrom(PeriodicSpinLattice reference)
        {
            //Make sure that the copy is actually possible
            if(reference.Width != Width) return false;
            if(reference.Height != Height) return false;

            //Perform the data copy
            for (int i=0; i < Width; ++i) {
                for (int j=0; j < Height; ++j) {
                    this[i, j] = reference [i, j];
                }
            }

            return true;
        }
        //Check if two spin lattices have identical contents
        public bool Equals(PeriodicSpinLattice reference)
        {
            for (int i=0; i < Width; ++i) {
                for (int j=0; j < Height; ++j) {
                    if (this[i, j] != reference[i, j])
                    {
                        return false;
                    }
                }
            }

            return true;
        }