Como tornar o dever de casa mais divertido, MATLAB para Ruby

Eu queria animar meu dever de casa EletroMagnetismo na semana passada, o que exigiu que fizéssemos um pouco de MATLAB. Infelizmente, não tenho o MATLAB porque não é o sistema operacional e não queria ir para a escola para usar um computador, então fiz alguns macacos de patch para fazer meu código Ruby parecer o MATLAB. Agora posso apenas copiar o código MATLAB, fazer algumas alterações e executá-lo. Apenas algumas mudanças são necessárias neste ponto para converter o MATLAB para Ruby:

[1 2 3] -> [1, 2, 3]  # arrays
x
^2 -> x**2 # exponents
% -> # # comments

Atualização: ^tem menos precedência do **que o motivo pelo qual eu continuei **. Comente se você sabe como alterar a precedência do operador. Não consegui encontrar muito.

Aqui está o arquivo que eu exijo:

#matlab_helper.rb
$VERBOSE
= nil # surpress constant redefinition warnings
include
Math

def norm(vector)
sqrt vector
.map{ |x| x**2 }.inject(0, &:+)
end

class Array
def +(op)
self.zip(op).map { |a, b| a + b }
end

def -(op)
self.zip(op).map { |a, b| a - b }
end

def /(op)
self.map { |a| a / op }
end
end

class Float
alias_method
:mult, :*

def *(op)
if op.is_a? Array
op
.map { |a| self * a }
else
mult op

end
end
end

class Fixnum
alias_method
:mult, :*

def *(op)
if op.is_a? Array
op
.map { |a| self * a }
else
mult op

end
end
end

def pi
PI

end

E meu dever de casa convertido do MATLAB:

#hw.rb
require
'./matlab_helper'

# clc #clear the command line
# clear #remove all previous variables
Q1
= 8e-9 #charges on Q1
Q2
= 8e-9 #charges on Q2
pL
= 2e-9 #charge density of the line
Epsilon_o = 8.8419e-12 #Permitivity of free space

P
= [2, 3, 4] #coordinates of observation point
A
= [0, 0, 1] #coordinates of Q1
B
= [0, 0, -1] #coordinates of Q2
C
= [2, 0, 0] #coordinates of the center of the line charge

Number_of_L_Steps = 100000 #the steps of L

##the following routine calculates the electric fields at the
##observation point generated by the point charges
R1
= P - A #the vector pointing from Q1 to the observation point
R2
= P - B #the vector pointing from Q2 to the observation point

R1Mag
= norm(R1) #the magnitude of R1
R2Mag
= norm(R2) #the magnitude of R1
E1
= Q1 / (4 * pi * Epsilon_o * R1Mag**3) * R1 #the electric field generated by Q1
E2
= Q2 / (4 * pi * Epsilon_o * R2Mag**3) * R2 #the electric field generated by Q2

##the following routine calculates the electric field at the
##observation point generated by the line charge
d
= norm(P - C) #the distance from the observation point to the center of the line
length
= 100 * d #the length of the line
dL_V
= length / Number_of_L_Steps * [1, 0, 0] #vector of a segment
dL
= norm(dL_V) #length of a segment

EL
= [0, 0, 0] #initialize the electric field generated by EL
C_segment
= C - (Number_of_L_Steps / 2 * dL_V - dL_V / 2) #the center of the first segment

for i in (1..Number_of_L_Steps)
R
= P - C_segment #the vector seen from the center of the first segment to the observation point
RMag = norm(R) #the magnitude of the vector R
EL
= EL + dL * pL / (4 * pi * Epsilon_o * RMag**3) * R #get contibution from each segment
C_segment
= C_segment + dL_V #the center of the i-th segment
end

E
= E1 + E2 + EL # the electric field at P

puts
"E = #{E}"

# $ ruby hw.rb
# E = [2.010238790127288, 7.334514610377015, 9.388970095358529]

Ele é executado em cerca de 2 segundos com 100.000 passos, mas é Ruby!

Observação: incluí apenas os operadores necessários para concluir meu dever de casa, portanto, algumas combinações foram deixadas de fora.