Parallel the particle swarm optimization in Julia - multithreading

I wrote the particle swarm optimization algorithm in Julia, and I tried to use Threads to accelerate the computation for each population.
Here is the code
function uniform(dim::Int, lb::Array{Float64, 1}, ub::Array{Float64, 1})
arr = rand(Float64, dim)
#inbounds for i in 1:dim; arr[i] = arr[i] * (ub[i] - lb[i]) + lb[i] end
return arr
end
function initialize_particles(problem, population)
dim = problem.dim
lb = problem.lb
ub = problem.ub
cost_func = problem.cost_func
gbest_position = uniform(dim, lb, ub)
gbest = Gbest(gbest_position, cost_func(gbest_position))
particles = []
for i in 1:population
position = uniform(dim, lb, ub)
velocity = zeros(dim)
cost = cost_func(position)
best_position = copy(position)
best_cost = copy(cost)
push!(particles, Particle(position, velocity, cost, best_position, best_cost))
if best_cost < gbest.cost
gbest.position = copy(best_position)
gbest.cost = copy(best_cost)
end
end
return gbest, particles
end
function PSO(problem; max_iter=100,population=100,c1=1.4962,c2=1.4962,w=0.7298,wdamp=1.0)
dim = problem.dim
lb = problem.lb
ub = problem.ub
cost_func = problem.cost_func
gbest, particles = initialize_particles(problem, population)
# main loop
for iter in 1:max_iter
#threads for i in 1:population
particles[i].velocity .= w .* particles[i].velocity .+
c1 .* rand(dim) .* (particles[i].best_position .- particles[i].position) .+
c2 .* rand(dim) .* (gbest.position .- particles[i].position)
particles[i].position .= particles[i].position .+ particles[i].velocity
particles[i].position .= max.(particles[i].position, lb)
particles[i].position .= min.(particles[i].position, ub)
particles[i].cost = cost_func(particles[i].position)
if particles[i].cost < particles[i].best_cost
particles[i].best_position = copy(particles[i].position)
particles[i].best_cost = copy(particles[i].cost)
if particles[i].best_cost < gbest.cost
gbest.position = copy(particles[i].best_position)
gbest.cost = copy(particles[i].best_cost)
end
end
end
w = w * wdamp
if iter % 50 == 1
println("Iteration " * string(iter) * ": Best Cost = " * string(gbest.cost))
println("Best Position = " * string(gbest.position))
println()
end
end
gbest, particles
end
Obviously, it is not thread-safe in main loop of PSO. This is because the position of gbest needs to be modified when computing.
I tried to use Atomic, but the position of each particle is an array. So this method is not suitable.
The Lock needs initialization, so it also won't work.
I also tried to use Floop, but it went wrong.
So is there a way to make sure the data is locked when doing parallel computation?
Thank you for your time!
Wang

There is no need to lock variables. When you are doing parallel calculations you can always think in the terms of Split-Combine strategy (sorry just invent this term in analogy with DataFrames calculation, you may also call it Map-Reduce approach). The idea is that you split calculations around different threads and do them independently and on the final stage you combine results together on a single thread. So your code can look like this (there can be syntax errors, since I can't run the code without Particle and other definitions, but I hope it is enough to give the idea)
function minby(itr; by=identity, init=nothing)
init = isnothing(init) ? pop!(itr) : init
mapreduce(x->(by(x)=>x), (x,y)->(first(x)>first(y)) ? y : x, itr; init=by(init)=>init).second
end
function PSO(problem; max_iter=100,population=100,c1=1.4962,c2=1.4962,w=0.7298,wdamp=1.0)
dim = problem.dim
lb = problem.lb
ub = problem.ub
cost_func = problem.cost_func
gbest, particles = initialize_particles(problem, population)
# main loop
for iter in 1:max_iter
gbests = fill((gbest.cost, 0), Threads.nthreads())
#threads for i in 1:population
particles[i].velocity .= w .* particles[i].velocity .+
c1 .* rand(dim) .* (particles[i].best_position .- particles[i].position) .+
c2 .* rand(dim) .* (gbest.position .- particles[i].position)
particles[i].position .= particles[i].position .+ particles[i].velocity
particles[i].position .= max.(particles[i].position, lb)
particles[i].position .= min.(particles[i].position, ub)
particles[i].cost = cost_func(particles[i].position)
if particles[i].cost < particles[i].best_cost
particles[i].best_position = copy(particles[i].position)
particles[i].best_cost = copy(particles[i].cost)
if particles[i].best_cost < gbests[Threads.threadid()][1]
gbests[Threads.threadid()] = (particles[i].best_cost, i)
end
end
end
gbest1 = minby(gbests, by = x -> x[1])
if gbest1[2] != 0
idx = gbest1[2]
gbest.position = copy(particles[idx].best_position)
gbest.cost = copy(particles[idx].best_cost)
end
w = w * wdamp
if iter % 50 == 1
println("Iteration " * string(iter) * ": Best Cost = " * string(gbest.cost))
println("Best Position = " * string(gbest.position))
println()
end
end
gbest, particles
end
By the way, you may find that package UnPack.jl is rather convinient. Instead of manual assignments, you can do just
using UnPack
function PSO(problem; max_iter=100,population=100,c1=1.4962,c2=1.4962,w=0.7298,wdamp=1.0)
#unpack dim, lb, ub, cost_func = problem
....

Related

What does a second equals = within vba variable assignment do?

Perplexed by the function of using a second = sign in vba. eg. s = Int(xVal) + (xVal = n + 1)
I had been deciphering some code and came across the following line which is perplexing me somewhat and despite some extensive research and debugging I seem to be struggling to find the answer:
s = Int(xVal) + (xVal = n + 1)
and
p(i, 3) = A(i)(s + 3 + (s = n)) + (s = n) * (p(i, 1) - p(i, 2))
My question is what is the function of the comparisons within the parentheses after the first assignment = sign?
TIA
(s = n)
If both s and n have the same value then this evaluates to True, which can be coerced to its underlying value of -1 by other arithmetic operations.
Eg:
? True * 1 '>> -1
? False * 1 '>> 0
So this:
s = Int(xVal) + (xVal = n + 1)
is like writing:
If xVal = n + 1 Then
s = Int(xVal) + -1
else
s = Int(xVal) + 0
end if
or:
s = Int(xVal) + IIf(xVal = n + 1, -1, 0)

Getting all strings in a lua script

I'm trying to encode some strings in my lua script, and since that I have a lua script with over 200k characters, encrypting each string query in the script with a function such as this example below
local string = "stackoverflow"
local string = [[stackoverflow]]
local string = [==[stackoverflow]==]
local string = 'stackoverflow'
to
local string=decode("jkrtbfmviwcfn",519211)
Trying to provide all above results to thread through a gsub and have the gsub encode the string text with a random offset number.
So far, I was only capable of gsubbing full quotation marks through.
function encode(x,offset,a)
for char in string.gmatch(x, "%a") do
local encrypted = string.byte(char) + offset
while encrypted > 122 do
encrypted = encrypted - 26
end
while encrypted < 97 do
encrypted = encrypted + 26
end
a[#a+1] = string.char(encrypted)
end
return table.concat(a)
end
luacode=[==[thatstring.Value="Encryptme!" testvalue.Value=[[string with
a linebreak]] string.Text="STOP!"]==]
luacode=luacode:gsub([=["(.-)"]=],function(s)
print("Caught "..s)
local offset=math.random(1,4)
local encoded=encode(s,offset,{})
return [[decode("]]..encoded..[[",]]..offset..[[)]]
end)
print("\n"..luacode)
With its output being
Caught Encryptme!
Caught STOP!
thatstring.Value=decode("crgvctxqi",4) testvalue.Value=[[string with
a linebreak]] string.Text=decode("opkl",2)
Any better solutions?
local function strings_and_comments(lua_code, callback)
-- lua_code must be valid Lua code (an error may be raised on syntax error)
-- callback will be invoked as callback(object_type, value, start_pos, end_pos)
-- callback("comment", comment_text, start_pos, end_pos) -- for comments
-- callback("string", string_value, start_pos, end_pos) -- for string literals
local objects = {} -- possible comments and string literals in the code
-- search for all start positions of comments (with false positives)
for pos, br1, eq, br2 in lua_code:gmatch"()%-%-(%-*%[?)(=*)(%[?)" do
table.insert(objects, {start_pos = pos,
terminator = br1 == "[" and br2 == "[" and "]"..eq.."]" or "\n"})
end
-- search for all start positions of string literals (with false positives)
for pos, eq in lua_code:gmatch"()%[(=*)%[[%[=]*" do
table.insert(objects, {is_string = true, start_pos = pos,
terminator = "]"..eq.."]"})
end
for pos, quote in lua_code:gmatch"()(['\"])" do
table.insert(objects, {is_string = true, start_pos = pos, quote = quote})
end
table.sort(objects, function(a, b) return a.start_pos < b.start_pos end)
local end_pos = 0
for _, object in ipairs(objects) do
local start_pos, ok, symbol = object.start_pos
if start_pos > end_pos then
if object.terminator == "\n" then
end_pos = lua_code:find("\n", start_pos + 1, true) or #lua_code
-- exclude last spaces and newline
while lua_code:sub(end_pos, end_pos):match"%s" do
end_pos = end_pos - 1
end
elseif object.terminator then
ok, end_pos = lua_code:find(object.terminator, start_pos + 1, true)
assert(ok, "Not a valid Lua code")
else
end_pos = start_pos
repeat
ok, end_pos, symbol = lua_code:find("(\\?.)", end_pos + 1)
assert(ok, "Not a valid Lua code")
until symbol == object.quote
end
local value = lua_code:sub(start_pos, end_pos):gsub("^%-*%s*", "")
if object.terminator ~= "\n" then
value = assert((loadstring or load)("return "..value))()
end
callback(object.is_string and "string" or "comment", value, start_pos, end_pos)
end
end
end
local inv256
local function encode(str)
local seed = math.random(0x7FFFFFFF)
local result = '",'..seed..'))'
if not inv256 then
inv256 = {}
for M = 0, 127 do
local inv = -1
repeat inv = inv + 2
until inv * (2*M + 1) % 256 == 1
inv256[M] = inv
end
end
repeat
seed = seed * 3
until seed > 2^43
local K = 8186484168865098 + seed
result = '(decode("'..str:gsub('.',
function(m)
local L = K % 274877906944 -- 2^38
local H = (K - L) / 274877906944
local M = H % 128
m = m:byte()
local c = (m * inv256[M] - (H - M) / 128) % 256
K = L * 21271 + H + c + m
return ('%02x'):format(c)
end
)..result
return result
end
function hide_strings_in_lua_code(lua_code)
local text = { [[
local function decode(str, seed)
repeat
seed = seed * 3
until seed > 2^43
local K = 8186484168865098 + seed
return (str:gsub('%x%x',
function(c)
local L = K % 274877906944 -- 2^38
local H = (K - L) / 274877906944
local M = H % 128
c = tonumber(c, 16)
local m = (c + (H - M) / 128) * (2*M + 1) % 256
K = L * 21271 + H + c + m
return string.char(m)
end
))
end
]] }
local pos = 1
strings_and_comments(lua_code,
function (object_type, value, start_pos, end_pos)
if object_type == "string" then
table.insert(text, lua_code:sub(pos, start_pos - 1))
table.insert(text, encode(value))
pos = end_pos + 1
end
end)
table.insert(text, lua_code:sub(pos))
return table.concat(text)
end
Usage:
math.randomseed(os.time())
-- This is the program to be converted
local luacode = [===[
print"Hello world!"
print[[string with
a linebreak]]
local str1 = "stackoverflow"
local str2 = [[stackoverflow]]
local str3 = [==[stackoverflow]==]
local str4 = 'stackoverflow'
print(str1)
print(str2)
print(str3)
print(str4)
]===]
-- Conversion
print(hide_strings_in_lua_code(luacode))
Output (converted program)
local function decode(str, seed)
repeat
seed = seed * 3
until seed > 2^43
local K = 8186484168865098 + seed
return (str:gsub('%x%x',
function(c)
local L = K % 274877906944 -- 2^38
local H = (K - L) / 274877906944
local M = H % 128
c = tonumber(c, 16)
local m = (c + (H - M) / 128) * (2*M + 1) % 256
K = L * 21271 + H + c + m
return string.char(m)
end
))
end
print(decode("ef869b23b69b7fbc7f89bbe7",2686976))
print(decode("c2dc20f7061c452db49302f8a1d9317aad1009711e0984",1210253312))
local str1 = (decode("84854df4599affe9c894060431",415105024))
local str2 = (decode("a5d7db792f0b514417827f34e3",1736704000))
local str3 = (decode("6a61bcf9fd6f403ed1b4846e58",1256259584))
local str4 = (decode("cad56d9dea239514aca9c8b8e0",1030488064))
print(str1)
print(str2)
print(str3)
print(str4)
Output of output (output produced by the converted program)
Hello world!
string with
a linebreak
stackoverflow
stackoverflow
stackoverflow
stackoverflow

Recursion code in VBA

I am trying to run this code to calculate Q(n) at different Tn in the Equation 16.4 in the attached picture.But its not giving me the correct output. I would appreciate any help. Note: delta1=delta2 =...deltan = dt=1 ( I have taken here ) and further divided S term by 10000 just because in the Equation it is in basis point i.e. 100th part of 1 %.
Function Bootstrap(S As Range, Z As Range, L As Double) As Double
Dim j As Integer
Dim a As Variant
Dim b As Variant
Dim n As Integer
Dim Q() As Double
Dim sum As Double
Dim P As Double
Dim dt As Double
n = Application.WorksheetFunction.Max(S.Columns.Count, Z.Columns.Count)
a = S.Value
b = Z.Value
dt = 1
sum = 0
ReDim Q(0 To n)
Q(0) = 1
For j = 1 To n - 1
P = (b(1, j) * (L * Q(j - 1) - (L + dt * a(1, n) / 10000) * Q(j))) / (b(1, n) * (L + a(1, n) * dt / 10000)) + Q(n - 1) * L / (L + a(1, n) * dt / 10000)
sum = sum + P
Q(n) = sum
Next j
Bootstrap = sum
End Function
To solve a recursive function you can write it this way, for example
Function Factorial(n as long) as long
If n = 1 Then
Factorial = 1
Else
Factorial = n * Factorial(n-1)
End If
End function
Yes, you can see For...Loop can also do the Factorial calculation, but in your case, its much easier to use recursive solution.
Besides Eq 16.4 is intentionally written as a recursive function. It is not written as a summation function because it is harder to do so. If given to you is a summation function, then you can apply the For...Loop solution.
Hope this helps.
EDIT
Function Q(n as long) as double
If n = 1 Then
Q = 5
Else
Q = Z * ( L * Q_t - (L + d * S) * Q(n-1) ) / ( Z * ( L + d * S ) )
End If
End Function
Notice that the function Q keep calling itself in Q(n-1) when n>1. That is called recursive solution.
(Check the formula. I might copy it wrong)

OpenMP block gives false results

I would appreciate your point of view where I might did wrong using OpenMP.
I parallelized this code pretty strait forward - yet even with single thread (i.e., call omp_set_num_threads(1)) I get wrong results.
I have checked with Intel Inspector, and I do not have a race condition, yet the Inspector tool indicated as a warning that a thread might approach other thread stack (I have this warning in other code I have, and it runs well with OpenMP). I do not think this is the problem.
SUBROUTINE GR(NUMBER_D, RAD_D, RAD_CC, SPECT)
use TERM,only: DENSITY, TEMPERATURE, VISCOSITY, WATER_DENSITY, &
PRESSURE, D_HOR, D_VER, D_TEMP, QQQ, UMU
use SATUR,only: FF, A1, A2, AAA, BBB, SAT
use DELTA,only: DDM, DT
use CONST,only: PI, G
IMPLICIT NONE
INTEGER,INTENT(IN) :: NUMBER_D
DOUBLE PRECISION,INTENT(IN) :: RAD_CC(NUMBER_D), SPECT(NUMBER_D)
DOUBLE PRECISION,INTENT(INOUT) :: RAD_D(NUMBER_D)
DOUBLE PRECISION :: R3, DR3, C2, C0, P, Q, RAD_CR, SAT_CR, C4, A, &
C, D, CC, DD, CC2, DD2, RAD_ST, DRAA, DRA, DM, X1
INTEGER :: I
DDM = 0.0D0
!$OMP PARALLEL DO DEFAULT(SHARED) &
!$OMP PRIVATE(I,R3,DR3,C2,C0,P,Q,SAT,SAT_CR,C4,A) &
!$OMP PRIVATE (C,D,CC,DD,CC2,DD2,RAD_ST,DRAA,DRA,DM,RAD_CR,X1) &
!$OMP REDUCTION (+:DDM)
DO I=1,NUMBER_D
R3 = RAD_CC(I)**3
DR3 = RAD_D(I)**3-R3
IF(DR3.LT.1.0D-100) DR3 = 1.0D-100
C2 = -DSQRT(3.0D0*BBB*R3/AAA)
C0 = -R3
P = -0.3333333333D0*C2**2
Q = C0+0.074074074D0*C2**3
CALL CUBIC(P, Q, RAD_CR)
RAD_CR = RAD_CR - 0.3333333333D0*C2
SAT_CR = DEXP(AAA/RAD_CR-BBB*R3/(RAD_CR**3-R3))-1.0D0
DRA = DT*(SAT+1.0D0-DEXP(AAA/RAD_DROP(I)-BBB*R3/DR3))/ &
(FF*RAD_D(I))
IF(SAT.LT.SAT_CR) THEN
IF(DABS(SAT).LT.1.0D-10) THEN
P = -BBB*R3/AAA
Q = -R3
CALL CUBIC(P, Q, RAD_ST)
GO TO 22
END IF
C4 = DLOG(SAT+1.0D0)
A = -AAA/C4
C = (BBB-C4)*R3/C4
D = -A*R3
P = A*C-4.0D0*D
Q = -(A**2*D+C**2)
CALL CUBIC(P, Q, X1)
CC = DSQRT(A**2+4.D0*X1)
DD = DSQRT(X1**2-4.D0*D)
CC2 = 0.5D0*(A-CC)
IF(SAT.LT.0.0D0) THEN
DD2 = 0.5D0*(X1-DD)
RAD_ST = 0.5D0*(-CC2+DSQRT(CC2**2-4.0D0*DD2))
ELSE
DD2 = 0.5D0*(X1+DD)
RAD_ST = 0.5D0*(-CC2-DSQRT(CC2**2-4.0D0*DD2))
END IF
22 CONTINUE
DRAA = RAD_ST-RAD_D(I)
IF(ABS(DRAA).LT.ABS(DRA)) THEN
DRA = DRAA
DM = 1.3333333333333333D0*PI*WATER_DENSITY* &
(RAD_ST**3-RAD_D(I)**3)
ELSE
DM = 4.0D0*PI*WATER_DENSITY*RAD_D(I)**2*DRA
END IF
DDM = DDM+SPECT(I)*DM
RAD_D(I) = RAD_D(I) + DRA
ELSE
DM = 4.0D0*PI*WATER_DENSITY*RAD_D(I)**2*DRA
DDM = DDM+SPECT(I)*DM
RAD_D(I) = RAD_D(I) + DRA
END IF
END DO
!$OMP END PARALLEL DO
RETURN
END SUBROUTINE GR
SUBROUTINE CUBIC(P, Q, X)
IMPLICIT NONE
DOUBLE PRECISION,INTENT(IN) :: P, Q
DOUBLE PRECISION,INTENT(OUT) :: X
DOUBLE PRECISION :: DIS, PP, COSALFA,ALFA, QQ, U, V
DIS = (P/3.D0)**3+(0.5D0*Q)**2
IF(DIS.LT.0.0D0) THEN
PP = -P/3.0D0
COSALFA = -0.5D0*Q/DSQRT(PP**3)
ALFA = DACOS(COSALFA)
X = 2.0D0*DSQRT(PP)*DCOS(ALFA/3.0D0)
RETURN
ELSE
QQ = DSQRT(DIS)
U = -0.5D0*Q+QQ
V = -0.5D0*Q-QQ
IF(U.GE.0.0D0) THEN
U = U**0.333333333333333D0
ELSE
U = -(-U)**0.333333333333333D0
END IF
IF(V.GE.0.0D0) THEN
V = V**0.333333333333333D0
ELSE
V = -(-V)**0.333333333333333D0
END IF
X = U+V
END IF
RETURN
END SUBROUTINE CUBIC

Updating a string inside a callback

The following code is a graphic rendering of the Earth globe spinning eastward. I have two push buttons, Spin and Stop. Both share the same callback function, hAnimaCallback. In particular, this latter does not work. I pretend to use the strings (names) of the push buttons to create a switch that stops the movement. However, I can not get to change the string name inside the while loop and I do not understand why my method is wrong.
function example
fh = figure('Menu','none','Toolbar','none','Units','characters');
T = 0:pi/100:2*pi;
Y = zeros(numel(T),3);
Y(:,1) = 7000*cos(T);
Y(:,2) = 7000*sin(T);
hPanAni = uipanel('parent',fh,'Units','characters','Position',...
[22.6 10.4 53 23],'title','Controls','FontSize',11,...
'FontAngle','italic','FontWeight','bold');
hIniAni = uicontrol(hPanAni,'Style','pushbutton','Units','normalized',...
'Position',[0.14 0.64 0.5 0.12],'String','Spin',...
'FontSize',10,'Callback',#hAnimaCallback);
hFinAni = uicontrol(hPanAni,'Style','pushbutton','Units','normalized',...
'Position',[0.14 0.26 0.5 0.12],'String','Stop',...
'FontSize',10,'Callback',#hAnimaCallback);
hPantSim = uipanel('Parent',fh,'Units','characters',...
'Position',[107.87 8 157.447 42],'BorderType','none','title',...
'Screen','FontSize',11,'FontAngle','italic',...
'FontWeight','bold');
hPantSimInt = uipanel('Parent',hPantSim,'Units','normalized','Position',...
[0 0 1 1],'BorderType','line','BackgroundColor','black');
ah4 = axes('Parent',hPantSimInt,'Units','normalized','Position',...
[0 0 1 1],'Color','none','Visible','off','DataAspectRatio',...
[1 1 1],'NextPlot','add');
rotate3d(ah4);
hgrot = hgtransform('Parent',ah4);
Resf = 6378;
maptext = imread('tierra.jpg');
[X, map] = rgb2ind(maptext,128);
[x,y,z] = sphere(50);
x = Resf*x;
y = Resf*y;
z = Resf*z;
props.FaceColor= 'texture';
props.EdgeColor = 'none';
props.Parent = hgrot;
props.Cdata = flipud(X); % it is necesary to do this for getting the
% appropiate image on the sphere
hsurf = surface(x,y,z,props);
colormap(map);
axis equal;
view([71 14]);
set(gcf,'Renderer','opengl')
drawnow;
line('parent',ah4,'XData',Y(:,1),'YData',Y(:,2),'ZData',...
Y(:,3),'Color','red','LineWidth',2);
line('parent',ah4,'XData',Y(end,1),'YData',Y(end,2),...
'ZData',Y(end,3),'Marker','o','MarkerSize',6,'MarkerFaceColor','b');
axis square equal vis3d;
view(3);
handles.XLim = get(ah4,'XLim');
handles.YLim = get(ah4,'YLim');
handles.ZLim = get(ah4,'ZLim');
xmin = handles.XLim(1);
ymin = handles.YLim(1);
zmin = handles.ZLim(1);
xmax = handles.XLim(2);
ymax = handles.YLim(2);
zmax = handles.ZLim(2);
set(ah4, 'XLim', [xmin xmax],'YLim', [ymin ymax],'Zlim',[zmin zmax]);
az = 0;
function hAnimaCallback(hObject,evt)
while (ishandle(fh))
state = get(hObject,'String'), % state should change between the states of
% Spin and Stop but this does not occur
if (strcmp(state,'Stop'))
break;
else
az = az + 0.01745329252;
set(hgrot,'Matrix',makehgtform('zrotate',az));
drawnow;
end
end
end
end
It seems like you are running into some kind of race condition because of the repeated drawnow calls in the while loop. The state changes to Stop, when you press the Stop button, but it is to quick to notice. Basically, the while loop is running as fast as MATLAB can run. Instead of drawnow using a pause(0.1) command seems to work (with a little bit code logic changes):
az = 0;
spin = false;
function hAnimaCallback(hObject,~)
state = get(hObject,'String')
if strcmp(state, 'Spin')
spin = true;
else
spin = false;
end
while (spin)
az = az + 0.01745329252;
set(hgrot,'Matrix',makehgtform('zrotate',az));
pause(0.1);
end
end

Resources