Ok, first up, this is NOT for a class, test, or other student type activity.
I'm a scripter for a game, and am trying to implement the math library for all to use, and unfortunately, all I have available to me is very basic lua. The implemented version cannot be changed, and does not include any libraries. For those wondering, its for scripting in Fold.It.
Here's what I have...
math={}
math.fact = function(b) if(b==1)or(b==0) then return 1 end e=1 for c=b,1,-1 do e=e*c end return e end
math.pow = function(b,p) e=b if(p==0) then return 1 end if(p<0) then p=p*(-1) end for c=p,2,-1 do e=e*b end return e end
math.cos = function(b,p) e=0 p=p or 10 for i=1,p do e=e+(math.pow(-1,i)*math.pow(b,2*i)/math.fact(2*i)) end return e end
To clarify above, math.fact returns factorial, which is returning accurate to about 10 points of precision, and is a new function I've done to aid in cosine calculation.
The math.pow is also a new function to handle returning powers, also working as expected.
The issue is with the cosine function. Its returning unexpected values. Here's an easier to digest version (I've been writing my library stuff ultra lean)...
function math.cos(value,precision)
result=0
precision=precision or 10
for i=1,precision do
result=result+(math.pow(-1,i)*math.pow(value,2*i)/math.fact(2*i))
end
return e
end
The problem is, with those functions, for print(math.cos(90)) it returns 4.77135... when I'm expecting -0.44807... (based on calc in scientific mode, or using an online tool to cos(90)).
I'm also having issues with sin and tan, however they are similarly written to cos, which seems to have been done in many languages. If I can figure out what I'm doing wrong, I can get them all fixed.
EDIT: Corrected typo
First, your lua doesn't run. Second, you need to make your variables local. Third, cosine starts with a one.
The problem is because the Taylor series you are using only converges on the correct values of cosine close to zero. You would have to use a far more terms of the series to get it to handle 90 correctly. You can fix this for your implementation two ways:
Add a pi constant. Then use a while loop to adjust the value such that abs(value) < 2*pi:
math.pi = 3.14159265358
while value > math.pi*2 do
value = value - math.pi * 2
end
while value < -math.pi*2 do
value = value + math.pi * 2
end
Or - find or implement a version of fmod in lua.
Here is the corrected code (you can minify it):
math={}
math.fact = function(b)
if(b==1)or(b==0) then
return 1
end
local e=1
for c=b,1,-1 do
e=e*c
end
return e
end
math.pow = function(b,p)
local e=b
if(p==0) then
return 1
end
if(p<0) then
p=p*(-1)
end
for c=p,2,-1 do
e=e*b
end
return e
end
math.cos = function(b,p)
local e=1
b = math.correctRadians(b)
p=p or 10
for i=1,p do
e=e+(math.pow(-1,i)*math.pow(b,2*i)/math.fact(2*i))
end
return e
end
math.pi = 3.1415926545358
math.correctRadians = function( value )
while value > math.pi*2 do
value = value - math.pi * 2
end
while value < -math.pi*2 do
value = value + math.pi * 2
end
return value
end
interactive lua run:
imac:~ root$ lua -i temp.lua
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> print( math.cos( 90 ) )
-0.44807359244883
>
Related
I want to have objects interact with specific interactions depending on their type.
Example problem: I have four particles, two are type A, and 2 are type B. when type A's interact I want to use the function
function interaction(parm1, parm2)
return parm1 + parm2
end
when type B's interact I want to use the function
function interaction(parm1, parm2)
return parm1 * parm2
end
when type A interacts with type B I want to use function
function interaction(parm1, parm2)
return parm1 - parm2
end
These functions are purposefully over simple.
I want to calculate a simple summation that depends on pairwise interactions:
struct part
parm::Float64
end
# part I need help with:
# initialize a list of length 4, where the entries are `struct part`, and the abstract types
# are `typeA` for the first two and `typeB` for the second two. The values for the parm can be
# -1.0,3, 4, 1.5 respectively
energy = 0.0
for i in range(length(particles)-1)
for j = i+1:length(particles)
energy += interaction(particles[i].parm, particles[j].parm)
end
end
println(energy)
assuming the use of parameters being particle[1].parm = -1, particle[2].parm = 3, particle[3].parm = 4, particle[4].parm = 1.5, energy should account for the interactions of
(1,2) = -1 + 3 = 2
(1,3) = -1 - 4 = -5
(1,4) = -1 - 1.5 = -2.5
(2,3) = 3 - 4 = -1
(2,4) = 3 - 1.5 = 1.5
(3,4) = 4 * 1.5 = 6
energy = 1
Doing this with if statements is almost trivial but not extensible. I am after a clean, tidy Julia approach...
You can do this (I use the simplest form of the implementation as in this case it is enough and it is explicit what happens I hope):
struct A
parm::Float64
end
struct B
parm::Float64
end
interaction(p1::A, p2::A) = p1.parm + p2.parm
interaction(p1::B, p2::B) = p1.parm * p2.parm
interaction(p1::A, p2::B) = p1.parm - p2.parm
interaction(p1::B, p2::A) = p1.parm - p2.parm # I added this rule, but you can leave it out and get MethodError if such case happens
function total_energy(particles)
energy = 0.0
for i in 1:length(particles)-1
for j = i+1:length(particles)
energy += interaction(particles[i], particles[j])
end
end
return energy
end
particles = Union{A, B}[A(-1), A(3), B(4), B(1.5)] # Union makes sure things are compiled to be fast
total_energy(particles)
I have no idea how to do this in your language, but what you need is an analogue to what we call the strategy pattern in object-oriented programming. A strategy is a pluggable, reusable algorithm. In Java I’d make an interface like:
interface Interaction<A, B>
{
double interact(A a, B b)
}
Then implement this three times and reuse those parts wherever you need things to interact. Another method can take an Interaction and use it without knowing how it’s implemented. I think this is the effect you’re after. Sorry I don’t know how to translate into your dialect.
I'm using NLopt for a constrained maximization problem. Regardless of the algorithm or start values, the optimization program is force stopped even before the first iteration (or so I assume because it gives me the initial value). I've attached my code here. I'm trying to find probabilities attached to a grid such that a function is maximized under some constraints. Any help is appreciated.
uk = x -> x^0.5
function objective(u,p,grd)
-p'*u.(grd)
end
function c3(grd,p)
c =[]
d =[]
for i=1:length(grd)
push!(c,quadgk(x -> (i-x)*(x <= i ? 1 : 0),0,1)[1])
push!(d,sum(p[1:i]'*(grd[1:i] .- grd[i])))
end
return append!(d-c,-p)
end
function c4(grd,p)
return (grd .* p)-quadgk(x,0,1)
end
grd = n -> collect(0:1/n:1)
opt = Opt(:LD_SLSQP,11)
inequality_constraint!(opt, p -> c3(grd(10),p))
inequality_constraint!(opt, p -> -p)
equality_constraint!(opt, p -> sum(p)-1)
equality_constraint!(opt, p -> c4(grd(10),p))
opt.min_objective = p -> objective(-uk, p, grd(10))
k = push!(ones(11)*(1/11))
(minf,minx,ret) = optimize(opt, k)
I'm not a julia developer, but I only know this, if you need exit before complete the loop for is not your best choice, you need do a while with a sentinel variable.
here you have an article that explain you how while with sentinels works
and here you have a julia example changing your for to a while with a sentinel that exit after the third loop
i = 1
third = 0
while i < length(grd) && third != 1
# of course you need change this, it is only an example that will exit in the 3 loop
if i == 3
third = 1
end
push!(c,quadgk(x -> (i-x)*(x <= i ? 1 : 0),0,1)[1])
push!(d,sum(p[1:i]'*(grd[1:i] .- grd[i])))
i += 1
end
UPDATE -- I figured it out. Turns out I am bad at math and visualizing 2d points. I wasn't setting south or east subdivisions correctly.
I have been trying to make a quadtree to track points in Love2d. I have the most of the code written, but I don't think the recursion is working properly.
I'm pretty new to the coding scene, so I really don't know where to start.
It seems to leave out points that go into the southeast quadrant.
I think as it goes recursively into the insert function it either looks at the parents point array or doesn't seem to go into all the insert functions.
local QuadTree = {}
QuadTree.__index = QuadTree
function QuadTree:new(boundary,capacity)
local quadTemp = {}
setmetatable(quadTemp, QuadTree)
if (not boundary) then
print('No boundary given to new QuadTree')
end
if (type(capacity) ~= 'number') then
print('Boundary should be a number')
end
if (capacity < 1) then
print('capacity should be greater than one')
end
quadTemp.boundary = boundary
quadTemp.capacity = capacity
quadTemp.points = {}
quadTemp.hasDivided = false
return quadTemp
end
function QuadTree:insert(p)
--If this point doesnt belong in this spot dont add it
if (not self.boundary:contains(p)) then
return false
elseif (#self.points<self.capacity) then
table.insert(self.points,p)
return true
elseif(not self.hasDivided) then
self:subdivide()
elseif(self.hasDivided) then
return self.northeast:insert(p) or
self.northwest:insert(p) or
self.southeast:insert(p) or
self.southwest:insert(p)
end
end
function QuadTree:subdivide()
local x = self.boundary.xpos
local y = self.boundary.ypos
local w = self.boundary.width / 2
local h = self.boundary.height / 2
local nw = Rectangle:new(x,y,w,h)
self.northwest = QuadTree:new(nw,self.capacity)
local ne = Rectangle:new(w,y,w,h)
self.northeast = QuadTree:new(ne,self.capacity)
local sw = Rectangle:new(x,h,w,h)
self.southwest = QuadTree:new(sw,self.capacity)
local se = Rectangle:new(w,h,w,h)
self.southeast = QuadTree:new(se,self.capacity)
self.hasDivided = true
end
function QuadTree:query(range,found)
--If we havent found any yet lets create a list incase we do
if (not found) then found = {} end
--If this cell doesnt contain the boundary then return an empty list
if (not range:intersects(self.boundary)) then
return found
end
for k,v in pairs(self.points) do
if (range:contains(v)) then
table.insert(found,v)
end
end
--If the current cell has divided we need to check its children
if (self.hasDivided) then
self.northwest:query(range,found)
self.northeast:query(range,found)
self.southwest:query(range,found)
self.southeast:query(range,found)
end
return found;
end
Like in R:
a <- 2
or even better
a ← 2
which should translate to
a = 2
and if possible respect method overloading.
= is overloaded (not in the multiple dispatch sense) a lot in Julia.
It binds a new variable. As in a = 3. You won't be able to use ← instead of = in this context, because you can't overload binding in Julia.
It gets lowered to setindex!. As in, a[i] = b gets lowered to setindex!(a, b, i). Unfortunately, setindex! takes 3 variables while ← can only take 2 variables. So you can't overload = with 3 variables.
But, you can use only 2 variables and overload a[:] = b, for example. So, you can define ←(a,b) = (a[:] = b) or ←(a,b) = setindex!(a,b,:).
a .= b gets lowered to (Base.broadcast!)(Base.identity, a, b). You can overload this by defining ←(a,b) = (a .= b) or ←(a,b) = (Base.broadcast!)(Base.identity, a, b).
So, there are two potentially nice ways of using ←. Good luck ;)
Btw, if you really want to use ← to do binding (like in 1.), the only way to do it is using macros. But then, you will have to write a macro in front of every single assignment, which doesn't look very good.
Also, if you want to explore how operators get lowered in Julia, do f(a,b) = (a .= b), for example, and then #code_lowered f(x,y).
No. = is not an operator in Julia, and cannot be assigned to another symbol.
Disclaimer: You are fully responsible if you will try my (still beginner's) experiments bellow! :P
MacroHelper is module ( big thanks to #Alexander_Morley and #DanGetz for help ) I plan to play with in future and we could probably try it here :
julia> module MacroHelper
# modified from the julia source ./test/parse.jl
function parseall(str)
pos = start(str)
exs = []
while !done(str, pos)
ex, pos = parse(str, pos) # returns next starting point as well as expr
ex.head == :toplevel ? append!(exs, ex.args) : push!(exs, ex)
end
if length(exs) == 0
throw(ParseError("end of input"))
elseif length(exs) == 1
return exs[1]
else
return Expr(:block, exs...) # convert the array of expressions
# back to a single expression
end
end
end;
With module above you could define simple test "language":
julia> module TstLang
export #tst_cmd
import MacroHelper
macro tst_cmd(a)
b = replace("$a", "←", "=") # just simply replacing ←
# in real life you would probably like
# to escape comments, strings etc
return MacroHelper.parseall(b)
end
end;
And by using it you could probably get what you want:
julia> using TstLang
julia> tst```
a ← 3
println(a)
a +← a + 3 # maybe not wanted? :P
```
3
9
What about performance?
julia> function test1()
a = 3
a += a + 3
end;
julia> function test2()
tst```
a ← 3
a +← a + 3
```
end;
julia> test1(); #time test1();
0.000002 seconds (4 allocations: 160 bytes)
julia> test2(); #time test2();
0.000002 seconds (4 allocations: 160 bytes)
If you like to see syntax highlight (for example in atom editor) then you need to use it differently:
function test3()
#tst_cmd begin
a ← 3
a ← a + a + 3 # parser don't allow you to use "+←" here!
end
end;
We could hope that future Julia IDEs could syntax highlight cmd macros too. :)
What could be problem with "solution" above? I am not so experienced julian so many things. :P (in this moment something about "macro hygiene" and "global scope" comes to mind...)
But what you want is IMHO good for some domain specific languages and not to redefine basic of language! It is because readability very counts and if everybody will redefine everything then it will end in Tower of Babel...
What happens for a global variable when running in the parallel mode?
I have a global variable, "to_be_optimized_parameterIndexSet", which is a vector of indexes that should be optimized using gamultiobj and I have set its value only in the main script(nowhere else).
My code works properly in serial mode but when I switch to parallel mode (using "matlabpool open" and setting proper values for 'gaoptimset' ) the mentioned global variable becomes empty (=[]) in the fitness function and causes this error:
??? Error using ==> parallel_function at 598
Error in ==> PF_gaMultiFitness at 15 [THIS LINE: constants(to_be_optimized_parameterIndexSet) = individual;]
In an assignment A(I) = B, the number of elements in B and
I must be the same.
Error in ==> fcnvectorizer at 17
parfor (i = 1:popSize)
Error in ==> gamultiobjMakeState at 52
Score =
fcnvectorizer(state.Population(initScoreProvided+1:end,:),FitnessFcn,numObj,options.SerialUserFcn);
Error in ==> gamultiobjsolve at 11
state = gamultiobjMakeState(GenomeLength,FitnessFcn,output.problemtype,options);
E rror in ==> gamultiobj at 238
[x,fval,exitFlag,output,population,scores] = gamultiobjsolve(FitnessFcn,nvars, ...
Error in ==> PF_GA_mainScript at 136
[x, fval, exitflag, output] = gamultiobj(#(individual)PF_gaMultiFitness(individual, initialConstants), ...
Caused by:
Failure in user-supplied fitness function evaluation. GA cannot continue.
I have checked all the code to make sure I've not changed this global variable everywhere else.
I have a quad-core processor.
Where is the bug? any suggestion?
EDIT 1: The MATLAB code in the main script:
clc
clear
close all
format short g
global simulation_duration % PF_gaMultiFitness will use this variable
global to_be_optimized_parameterIndexSet % PF_gaMultiFitness will use this variable
global IC stimulusMoment % PF_gaMultiFitness will use these variables
[initialConstants IC] = oldCICR_Constants; %initialize state
to_be_optimized_parameterIndexSet = [21 22 23 24 25 26 27 28 17 20];
LB = [ 0.97667 0.38185 0.63529 0.046564 0.23207 0.87484 0.46014 0.0030636 0.46494 0.82407 ];
UB = [1.8486 0.68292 0.87129 0.87814 0.66982 1.3819 0.64562 0.15456 1.3717 1.8168];
PopulationSize = input('Population size? ') ;
GaTimeLimit = input('GA time limit? (second) ');
matlabpool open
nGenerations = inf;
options = gaoptimset('PopulationSize', PopulationSize, 'TimeLimit',GaTimeLimit, 'Generations', nGenerations, ...
'Vectorized','off', 'UseParallel','always');
[x, fval, exitflag, output] = gamultiobj(#(individual)PF_gaMultiFitness(individual, initialConstants), ...
length(to_be_optimized_parameterIndexSet),[],[],[],[],LB,UB,options);
matlabpool close
some other piece of code to show the results...
The MATLAB code of the fitness function, "PF_gaMultiFitness":
function objectives =PF_gaMultiFitness(individual, constants)
global simulation_duration IC stimulusMoment to_be_optimized_parameterIndexSet
%THIS FUNCTION RETURNS MULTI OBJECTIVES AND PUTS EACH OBJECTIVE IN A COLUMN
constants(to_be_optimized_parameterIndexSet) = individual;
[smcState , ~, Time]= oldCICR_CompCore(constants, IC, simulation_duration,2);
targetValue = 1; % [uM]desired [Ca]i peak concentration
afterStimulus = smcState(Time>stimulusMoment,14); % values of [Ca]i after stimulus
peak_Ca_value = max(afterStimulus); % smcState(:,14) is [Ca]i
if peak_Ca_value < 0.8 * targetValue
objectives(1,1) = inf;
else
objectives(1, 1) = abs(peak_Ca_value - targetValue);
end
pkIDX = peakFinder(afterStimulus);
nPeaks = sum(pkIDX);
if nPeaks > 1
peakIndexes = find(pkIDX);
period = Time(peakIndexes(2)) - Time(peakIndexes(1));
objectives(1,2) = 1e5* 1/period;
elseif nPeaks == 1 && peak_Ca_value > 0.8 * targetValue
objectives(1,2) = 0;
else
objectives(1,2) = inf;
end
end
Global variables do not get passed from the MATLAB client to the workers executing the body of the PARFOR loop. The only data that does get sent into the loop body are variables that occur in the text of the program. This blog entry might help.
it really depends on the type of variable you're putting in. i need to see more of your code to point out the flaw, but in general it is good practice to avoid assuming complicated variables will be passed to each worker. In other words anything more then a primitive may need to be reinitialized inside a parallel routine or may need have specific function calls (like using feval for function handles).
My advice: RTM