Generate a GeoJSON heatmap using MongoDB map/reduce - ruby

I am visualising annual UK film screening using a javascript map that takes GeoJSON as an input. You can see it working for 2011 data here: http://screened2011.herokuapp.com
The generation of the GeoJSON is very inefficient - often taking 5+ seconds per "tile".
I have a Ruby app which queries MongoDB for a set of "screenings" within a bounding box (as requested by the JS) and then generates a two-dimensional array representing the total number of screenings that occurred within each of a 16x16. This is apparently the bottleneck - it's hitting the server and pulling down all of these screenings.
I'd like to replace this with a map/reduce query that aggregates the count of all screenings within a bounding box into a 16x16 array of values, but I'm not having much success - it's quite the task for my first map/reduce!
Here's a simplified version of my code with unrelated stuff taken out (it's awful, and if this weren't a hack coming to an end, I'd refactor):
get :boxed, :map => "/screenings/year/:year/quadrant/:area/bbox/:bbox", :provides => [:json, :jsonp], :cache => false do
box = parameter_box(params[:bbox]) # returns [[minx,miny],[maxx,maxy]]
year = params[:year].to_i
screenings = Screening.where(:location.within(:box) => box).where(:year => year)
jsonp Screening.heatmap(screenings, box, 16)
end
def self.heatmap screenings, box, scale
grid = []
min_x = box[0][0]
min_y = box[0][1]
max_x = box[1][0]
max_y = box[1][1]
box_width = max_x.to_f - min_x.to_f
box_height = max_y.to_f - min_y.to_f
return [] if box_width == 0 || box_height == 0
# Set up an empty GeoJSON-style array to hold the results
scalef = scale.to_f
(0..(scale - 1)).each do |i|
grid[i] = []
(0..(scale - 1)).each do |j|
box_min_x = min_x + (i * ( box_width / scalef ))
box_max_x = min_x + ((i + 1) * ( box_width / scalef ))
box_min_y = min_y + (j * ( box_height / scalef ))
box_max_y = min_y + ((j + 1) * ( box_height / scalef ))
grid[i][j] = {
:count => 0,
#:id => "#{box_min_x}_#{box_max_x}_#{box_min_y}_#{box_max_y}",
:coordinates => [
[
[box_min_x,box_min_y], [box_min_x, box_max_y], [box_max_x, box_max_y], [box_max_x, box_min_y], [box_min_x,box_min_y]
]
]
}
end
end
# This loop is the bottleneck and I'd like to replace with a map-reduce
screenings.only(:location, :total_showings).each do |screening|
x = (scale * ((screening.location[0] - min_x) / box_width)).floor
y = (scale * ((screening.location[1] - min_y) / box_height)).floor
raise if x > (scale - 1)
raise if y > (scale - 1)
grid[x][y][:count] += screening.total_showings.to_i
end
# This converts the resulting 16x16 into GeoJSON
places = []
grid.each do |x|
x.each do |p|
if p[:count].to_i > 0
properties = {}
properties[:total_showings] = p[:count]
places << {
"id" => p[:id],
"type" => "Feature",
"geometry" => {
"type" => "Polygon",
"coordinates" => p[:coordinates]
},
"properties"=> properties
}
end
end
end
{
"type" => "FeatureCollection",
"features" => places
}
end
I'm using Mongoid, so I could chain a mapreduce onto the screenings query, and I'm hoping that this would greatly speed up the process - but how should I go about getting something like the following to pass into this function?:
[
[1,20000,30,3424,53,66,7586,54543,76764,4322,7664,43242,43,435,32,643],
...
]
...based on several million records each in this structure (essentially summing the total_showings) for each one within a bounding box:
{"_id"=>BSON::ObjectId('50e481e653e6dfbc92057e8d'),
"created_at"=>2013-01-02 18:52:22 +0000,
"ended_at"=>Thu, 07 Jun 2012 00:00:00 +0100,
"events"=>["10044735484"],
"film_id"=>BSON::ObjectId('4f96a91153e6df5ebc001afe'),
"genre_ids"=>[],
"location"=>[-2.003309596016, 52.396317185921],
"performance_id"=>"9001923080",
"specialised"=>false,
"started_at"=>Fri, 01 Jun 2012 00:00:00 +0100,
"total_showings"=>1,
"updated_at"=>2013-01-02 18:52:22 +0000,
"venue_id"=>BSON::ObjectId('4f9500bf53e6df004000034d'),
"week"=>nil,
"year"=>2012}
Thanks in advance folks!

Related

Making a rectangle made out of a given set of rectangles sizes (get the size as closest as the given one)

I'm actually working on a ruby project and need some help.
I have these inputs :
sizeX and sizeY as an integer
rectangles, which is an array of arrays containing two integers.
I’ll take these values as example :
sizeX = 130
sizeY = 240
rectangles = [ [100,100], [100,150], [50,100], [50,50] ]
With the input i have, i need an algorithm that creates a new rectangle, made of the sizes given in rectangles, that will make a resulting size as closest as sizeX and sizeY. I’m gonna call the created rectangle size rectX and rectY.
This closest determination will be calculated like so :
abs(sizeX - rectX) + abs(sizeY - rectY)
So it returns the smallest total difference
Here are some rules of what the algorithm can and can’t do :
We can use multiple times the same rectangle
We can’t rotate a rectangle (In the case of the example, we can’t have 150x100)
We have to use the least rectangles possible
Here is an illustrated example of a result :
Here is another example if the rectangle [50,100] is not given in rectangles :
I have done some code, but it's not efficient, and is a pretty big mess :
# Returns the biggest cabinet from a given list
def getBiggestCabinet(cabinets)
cabinets.sort_by!{ |rect| rect.cabinetsize_w * rect.cabinetsize_h }.reverse!
return cabinets.first
end
# Returns number of cabinets that fits inside a given width & height + its gap
def getCabinetClosestMatch(width,height,cabinet)
countX = (width / cabinet.cabinetsize_w).floor
countY = (height / cabinet.cabinetsize_h).floor
gapX = width - countX * cabinet.cabinetsize_w
gapY = height - countY * cabinet.cabinetsize_h
return countX, countY, gapX, gapY
end
# Only takes on cabinet at a time
def getBestCabinetByLength(cabinets,gap,match,x_or_y)
sorted = cabinets.sort_by!{ |cabinet|
if x_or_y
return cabinet.cabinetsize_w - gap
else
return cabinet.cabinetsize_h - gap
end
}
bestLength = 0
sorted.each do |cabinet|
if x_or_y
if match.modulo(cabinet.cabinetsize_h) == 0
bestLength = cabinet.cabinetsize_h
break;
end
else
if match.modulo(cabinet.cabinetsize_w) == 0
bestLength = cabinet.cabinetsize_w
break;
end
end
end
return bestLength
end
def createCompatibleArrays(cabinets)
# group cabinets by width or height
cabinets_x = cabinets.group_by{ |c| c.caninetsize_w }.values
cabinets_y = cabinets.group_by{ |c| c.caninetsize_h }.values
return cabinets_x, cabinets_y
end
def getCabinetConfig(cabinets,width,height)
biggestCabinet = getBiggestCabinet(cabinets)
countX, countY, gapX, gapY = getCabinetClosestMatch(width,height,biggestCabinet)
current_width = width - gapX
current_height = height - gapY
cabinets = cabinets.where.not(id: biggestCabinet.id)
cabinets_gx, cabinets_gy = createCompatibleArrays(cabinets)
cabinets_gx.each do |c|
unless c[0].cabinetsize_h / 2 > gapY
end
end
end

StatsBase.sample() can't draw without replacement if FrequencyWeights() are provided

I'm trying to sample without replacement using StatsBase.sample() in Julia. Because I have my data in the following form I can use my counts as FrequencyWeights():
using StatsBase
data = ["red", "blue", "green"]
counts = [2000, 2000, 1]
balls = StatsBase.sample(data, FrequencyWeights(counts), 1000)
One problem with this is that StatsBase.sample() implicitly sets replace=true so this is possible:
countmap(balls)
Dict("blue" => 478,
"green" => 2, # <= two green balls?
"red" => 520)
Explicitly setting replace=false throws an error.
balls = StatsBase.sample(data, FrequencyWeights(counts), 1000, replace=false)
Cannot draw 3 samples from 1000 samples without replacement.
error(::String)#error.jl:33
var"#sample!#174"(::Bool, ::Bool, ::typeof(StatsBase.sample!), ::Random._GLOBAL_RNG, ::Vector{String}, ::StatsBase.FrequencyWeights{Int64, Int64, Vector{Int64}}, ::Vector{String})#sampling.jl:858
#sample#175#sampling.jl:871[inlined]
#sample#176#sampling.jl:874[inlined]
top-level scope#Local: 2[inlined]
Is my only solution here to reformat my data to a wide form like this? Because that seems very inefficient as my actual data set has a lot of counts.:
wide_data = [fill("red", 2000)..., fill("blue", 2000)..., "green"]
sample(wide_data, 1000, replace=false)
You could use something like this:
function mysample(data::AbstractVector, counts::AbstractVector, n::Integer)
#assert n <= sum(counts)
#assert firstindex(data) == 1
#assert firstindex(counts) == 1
res = similar(data, n)
fw = FrequencyWeights(copy(counts))
for i in 1:n
j = sample(axes(data, 1), fw)
res[i] = data[j]
fw.sum -= 1
fw.values[j] -= 1
end
return res
end

Filling a matrix using parallel processing in Julia

I'm trying to speed up the solution time for a dynamic programming problem in Julia (v. 0.5.0), via parallel processing. The problem involves choosing the optimal values for every element of a 1073 x 19 matrix at every iteration, until successive matrix differences fall within a tolerance. I thought that, within each iteration, filling in the values for each element of the matrix could be parallelized. However, I'm seeing a huge performance degradation using SharedArray, and I'm wondering if there's a better way to approach parallel processing for this problem.
I construct the arguments for the function below:
est_params = [.788,.288,.0034,.1519,.1615,.0041,.0077,.2,0.005,.7196]
r = 0.015
tau = 0.35
rho =est_params[1]
sigma =est_params[2]
delta = 0.15
gamma =est_params[3]
a_capital =est_params[4]
lambda1 =est_params[5]
lambda2 =est_params[6]
s =est_params[7]
theta =est_params[8]
mu =est_params[9]
p_bar_k_ss =est_params[10]
beta = (1+r)^(-1)
sigma_range = 4
gz = 19
gp = 29
gk = 37
lnz=collect(linspace(-sigma_range*sigma,sigma_range*sigma,gz))
z=exp(lnz)
gk_m = fld(gk,2)
# Need to add mu somewhere to k_ss
k_ss = (theta*(1-tau)/(r+delta))^(1/(1-theta))
k=cat(1,map(i->k_ss*((1-delta)^i),collect(1:gk_m)),map(i->k_ss/((1-delta)^i),collect(1:gk_m)))
insert!(k,gk_m+1,k_ss)
sort!(k)
p_bar=p_bar_k_ss*k_ss
p = collect(linspace(-p_bar/2,p_bar,gp))
#Tauchen
N = length(z)
Z = zeros(N,1)
Zprob = zeros(Float32,N,N)
Z[N] = lnz[length(z)]
Z[1] = lnz[1]
zstep = (Z[N] - Z[1]) / (N - 1)
for i=2:(N-1)
Z[i] = Z[1] + zstep * (i - 1)
end
for a = 1 : N
for b = 1 : N
if b == 1
Zprob[a,b] = 0.5*erfc(-((Z[1] - mu - rho * Z[a] + zstep / 2) / sigma)/sqrt(2))
elseif b == N
Zprob[a,b] = 1 - 0.5*erfc(-((Z[N] - mu - rho * Z[a] - zstep / 2) / sigma)/sqrt(2))
else
Zprob[a,b] = 0.5*erfc(-((Z[b] - mu - rho * Z[a] + zstep / 2) / sigma)/sqrt(2)) -
0.5*erfc(-((Z[b] - mu - rho * Z[a] - zstep / 2) / sigma)/sqrt(2))
end
end
end
# Collecting tauchen results in a 2 element array of linspace and array; [2] gets array
# Zprob=collect(tauchen(gz, rho, sigma, mu, sigma_range))[2]
Zcumprob=zeros(Float32,gz,gz)
# 2 in cumsum! denotes the 2nd dimension, i.e. columns
cumsum!(Zcumprob, Zprob,2)
gm = gk * gp
control=zeros(gm,2)
for i=1:gk
control[(1+gp*(i-1)):(gp*i),1]=fill(k[i],(gp,1))
control[(1+gp*(i-1)):(gp*i),2]=p
end
endog=copy(control)
E=Array(Float32,gm,gm,gz)
for h=1:gm
for m=1:gm
for j=1:gz
# set the nonzero net debt indicator
if endog[h,2]<0
p_ind=1
else
p_ind=0
end
# set the investment indicator
if (control[m,1]-(1-delta)*endog[h,1])!=0
i_ind=1
else
i_ind=0
end
E[m,h,j] = (1-tau)*z[j]*(endog[h,1]^theta) + control[m,2]-endog[h,2]*(1+r*(1-tau)) +
delta*endog[h,1]*tau-(control[m,1]-(1-delta)*endog[h,1]) -
(i_ind*gamma*endog[h,1]+endog[h,1]*(a_capital/2)*(((control[m,1]-(1-delta)*endog[h,1])/endog[h,1])^2)) +
s*endog[h,2]*p_ind
elem = E[m,h,j]
if E[m,h,j]<0
E[m,h,j]=elem+lambda1*elem-.5*lambda2*elem^2
else
E[m,h,j]=elem
end
end
end
end
I then constructed the function with serial processing. The two for loops iterate through each element to find the largest value in a 1072-sized (=the gm scalar argument in the function) array:
function dynam_serial(E,gm,gz,beta,Zprob)
v = Array(Float32,gm,gz )
fill!(v,E[cld(gm,2),cld(gm,2),cld(gz,2)])
Tv = Array(Float32,gm,gz)
# Set parameters for the loop
convcrit = 0.0001 # chosen convergence criterion
diff = 1 # arbitrary initial value greater than convcrit
while diff>convcrit
exp_v=v*Zprob'
for h=1:gm
for j=1:gz
Tv[h,j]=findmax(E[:,h,j] + beta*exp_v[:,j])[1]
end
end
diff = maxabs(Tv - v)
v=copy(Tv)
end
end
Timing this, I get:
#time dynam_serial(E,gm,gz,beta,Zprob)
> 106.880008 seconds (91.70 M allocations: 203.233 GB, 15.22% gc time)
Now, I try using Shared Arrays to benefit from parallel processing. Note that I reconfigured the iteration so that I only have one for loop, rather than two. I also use v=deepcopy(Tv); otherwise, v is copied as an Array object, rather than a SharedArray:
function dynam_parallel(E,gm,gz,beta,Zprob)
v = SharedArray(Float32,(gm,gz),init = S -> S[Base.localindexes(S)] = myid() )
fill!(v,E[cld(gm,2),cld(gm,2),cld(gz,2)])
# Set parameters for the loop
convcrit = 0.0001 # chosen convergence criterion
diff = 1 # arbitrary initial value greater than convcrit
while diff>convcrit
exp_v=v*Zprob'
Tv = SharedArray(Float32,gm,gz,init = S -> S[Base.localindexes(S)] = myid() )
#sync #parallel for hj=1:(gm*gz)
j=cld(hj,gm)
h=mod(hj,gm)
if h==0;h=gm;end;
#async Tv[h,j]=findmax(E[:,h,j] + beta*exp_v[:,j])[1]
end
diff = maxabs(Tv - v)
v=deepcopy(Tv)
end
end
Timing the parallel version; and using a 4-core 2.5 GHz I7 processor with 16GB of memory, I get:
addprocs(3)
#time dynam_parallel(E,gm,gz,beta,Zprob)
> 164.237208 seconds (2.64 M allocations: 201.812 MB, 0.04% gc time)
Am I doing something incorrect here? Or is there a better way to approach parallel processing in Julia for this particular problem? I've considered using Distributed Arrays, but it's difficult for me to see how to apply them to the present problem.
UPDATE:
Per #DanGetz and his helpful comments, I turned instead to trying to speed up the serial processing version. I was able to get performance down to 53.469780 seconds (67.36 M allocations: 103.419 GiB, 19.12% gc time) through:
1) Upgrading to 0.6.0 (saved about 25 seconds), which includes the helpful #views macro.
2) Preallocating the main array I'm trying to fill in (Tv), per the section on Preallocating Outputs in the Julia Performance Tips: https://docs.julialang.org/en/latest/manual/performance-tips/. (saved another 25 or so seconds)
The biggest remaining slow-down seems to be coming from the add_vecs function, which sums together subarrays of two larger matrices. I've tried devectorizing and using BLAS functions, but haven't been able to produce better performance.
In any event, the improved code for dynam_serial is below:
function add_vecs(r::Array{Float32},h::Int,j::Int,E::Array{Float32},exp_v::Array{Float32},beta::Float32)
#views r=E[:,h,j] + beta*exp_v[:,j]
return r
end
function dynam_serial(E::Array{Float32},gm::Int,gz::Int,beta::Float32,Zprob::Array{Float32})
v = Array{Float32}(gm,gz)
fill!(v,E[cld(gm,2),cld(gm,2),cld(gz,2)])
Tv = Array{Float32}(gm,gz)
r = Array{Float32}(gm)
# Set parameters for the loop
convcrit = 0.0001 # chosen convergence criterion
diff = 1 # arbitrary initial value greater than convcrit
while diff>convcrit
exp_v=v*Zprob'
for h=1:gm
for j=1:gz
#views Tv[h,j]=findmax(add_vecs(r,h,j,E,exp_v,beta))[1]
end
end
diff = maximum(abs,Tv - v)
v=copy(Tv)
end
return Tv
end
If add_vecs seems to be the critical function, writing an explicit for loop could offer more optimization. How does the following benchmark:
function add_vecs!(r::Array{Float32},h::Int,j::Int,E::Array{Float32},
exp_v::Array{Float32},beta::Float32)
#inbounds for i=1:size(E,1)
r[i]=E[i,h,j] + beta*exp_v[i,j]
end
return r
end
UPDATE
To continue optimizing dynam_serial I have tried to remove more allocations. The result is:
function add_vecs_and_max!(gm::Int,r::Array{Float64},h::Int,j::Int,E::Array{Float64},
exp_v::Array{Float64},beta::Float64)
#inbounds for i=1:gm
r[i] = E[i,h,j]+beta*exp_v[i,j]
end
return findmax(r)[1]
end
function dynam_serial(E::Array{Float64},gm::Int,gz::Int,
beta::Float64,Zprob::Array{Float64})
v = Array{Float64}(gm,gz)
fill!(v,E[cld(gm,2),cld(gm,2),cld(gz,2)])
r = Array{Float64}(gm)
exp_v = Array{Float64}(gm,gz)
# Set parameters for the loop
convcrit = 0.0001 # chosen convergence criterion
diff = 1.0 # arbitrary initial value greater than convcrit
while diff>convcrit
A_mul_Bt!(exp_v,v,Zprob)
diff = -Inf
for h=1:gm
for j=1:gz
oldv = v[h,j]
newv = add_vecs_and_max!(gm,r,h,j,E,exp_v,beta)
v[h,j]= newv
diff = max(diff, oldv-newv, newv-oldv)
end
end
end
return v
end
Switching the functions to use Float64 should increase speed (as CPUs are inherently optimized for 64-bit word lengths). Also, using the mutating A_mul_Bt! directly saves another allocation. Avoiding the copy(...) by switching the arrays v and Tv.
How do these optimizations improve your running time?
2nd UPDATE
Updated the code in the UPDATE section to use findmax. Also, changed dynam_serial to use v without Tv, as there was no need to save the old version except for the diff calculation, which is now done inside the loop.
Here's the code I copied-and-pasted, provided by Dan Getz above. I include the array and scalar definitions exactly as I ran them. Performance was: 39.507005 seconds (11 allocations: 486.891 KiB) when running #time dynam_serial(E,gm,gz,beta,Zprob).
using SpecialFunctions
est_params = [.788,.288,.0034,.1519,.1615,.0041,.0077,.2,0.005,.7196]
r = 0.015
tau = 0.35
rho =est_params[1]
sigma =est_params[2]
delta = 0.15
gamma =est_params[3]
a_capital =est_params[4]
lambda1 =est_params[5]
lambda2 =est_params[6]
s =est_params[7]
theta =est_params[8]
mu =est_params[9]
p_bar_k_ss =est_params[10]
beta = (1+r)^(-1)
sigma_range = 4
gz = 19 #15 #19
gp = 29 #19 #29
gk = 37 #25 #37
lnz=collect(linspace(-sigma_range*sigma,sigma_range*sigma,gz))
z=exp.(lnz)
gk_m = fld(gk,2)
# Need to add mu somewhere to k_ss
k_ss = (theta*(1-tau)/(r+delta))^(1/(1-theta))
k=cat(1,map(i->k_ss*((1-delta)^i),collect(1:gk_m)),map(i->k_ss/((1-delta)^i),collect(1:gk_m)))
insert!(k,gk_m+1,k_ss)
sort!(k)
p_bar=p_bar_k_ss*k_ss
p = collect(linspace(-p_bar/2,p_bar,gp))
#Tauchen
N = length(z)
Z = zeros(N,1)
Zprob = zeros(Float64,N,N)
Z[N] = lnz[length(z)]
Z[1] = lnz[1]
zstep = (Z[N] - Z[1]) / (N - 1)
for i=2:(N-1)
Z[i] = Z[1] + zstep * (i - 1)
end
for a = 1 : N
for b = 1 : N
if b == 1
Zprob[a,b] = 0.5*erfc(-((Z[1] - mu - rho * Z[a] + zstep / 2) / sigma)/sqrt(2))
elseif b == N
Zprob[a,b] = 1 - 0.5*erfc(-((Z[N] - mu - rho * Z[a] - zstep / 2) / sigma)/sqrt(2))
else
Zprob[a,b] = 0.5*erfc(-((Z[b] - mu - rho * Z[a] + zstep / 2) / sigma)/sqrt(2)) -
0.5*erfc(-((Z[b] - mu - rho * Z[a] - zstep / 2) / sigma)/sqrt(2))
end
end
end
# Collecting tauchen results in a 2 element array of linspace and array; [2] gets array
# Zprob=collect(tauchen(gz, rho, sigma, mu, sigma_range))[2]
Zcumprob=zeros(Float64,gz,gz)
# 2 in cumsum! denotes the 2nd dimension, i.e. columns
cumsum!(Zcumprob, Zprob,2)
gm = gk * gp
control=zeros(gm,2)
for i=1:gk
control[(1+gp*(i-1)):(gp*i),1]=fill(k[i],(gp,1))
control[(1+gp*(i-1)):(gp*i),2]=p
end
endog=copy(control)
E=Array(Float64,gm,gm,gz)
for h=1:gm
for m=1:gm
for j=1:gz
# set the nonzero net debt indicator
if endog[h,2]<0
p_ind=1
else
p_ind=0
end
# set the investment indicator
if (control[m,1]-(1-delta)*endog[h,1])!=0
i_ind=1
else
i_ind=0
end
E[m,h,j] = (1-tau)*z[j]*(endog[h,1]^theta) + control[m,2]-endog[h,2]*(1+r*(1-tau)) +
delta*endog[h,1]*tau-(control[m,1]-(1-delta)*endog[h,1]) -
(i_ind*gamma*endog[h,1]+endog[h,1]*(a_capital/2)*(((control[m,1]-(1-delta)*endog[h,1])/endog[h,1])^2)) +
s*endog[h,2]*p_ind
elem = E[m,h,j]
if E[m,h,j]<0
E[m,h,j]=elem+lambda1*elem-.5*lambda2*elem^2
else
E[m,h,j]=elem
end
end
end
end
function add_vecs_and_max!(gm::Int,r::Array{Float64},h::Int,j::Int,E::Array{Float64},
exp_v::Array{Float64},beta::Float64)
maxr = -Inf
#inbounds for i=1:gm r[i] = E[i,h,j]+beta*exp_v[i,j]
maxr = max(r[i],maxr)
end
return maxr
end
function dynam_serial(E::Array{Float64},gm::Int,gz::Int,
beta::Float64,Zprob::Array{Float64})
v = Array{Float64}(gm,gz)
fill!(v,E[cld(gm,2),cld(gm,2),cld(gz,2)])
Tv = Array{Float64}(gm,gz)
r = Array{Float64}(gm)
exp_v = Array{Float64}(gm,gz)
# Set parameters for the loop
convcrit = 0.0001 # chosen convergence criterion
diff = 1.0 # arbitrary initial value greater than convcrit
while diff>convcrit
A_mul_Bt!(exp_v,v,Zprob)
diff = -Inf
for h=1:gm
for j=1:gz
Tv[h,j]=add_vecs_and_max!(gm,r,h,j,E,exp_v,beta)
diff = max(abs(Tv[h,j]-v[h,j]),diff)
end
end
(v,Tv)=(Tv,v)
end
return v
end
Now, here's another version of the algorithm and inputs. The functions are similar to what Dan Getz suggested, except that I use findmax rather than an iterated max function to find the array maximum. In the input construction, I am using both Float32 and mixing different bit-types together. However, I've consistently achieved better performance this way: 24.905569 seconds (1.81 k allocations: 46.829 MiB, 0.01% gc time). But it's not clear at all why.
using SpecialFunctions
est_params = [.788,.288,.0034,.1519,.1615,.0041,.0077,.2,0.005,.7196]
r = 0.015
tau = 0.35
rho =est_params[1]
sigma =est_params[2]
delta = 0.15
gamma =est_params[3]
a_capital =est_params[4]
lambda1 =est_params[5]
lambda2 =est_params[6]
s =est_params[7]
theta =est_params[8]
mu =est_params[9]
p_bar_k_ss =est_params[10]
beta = Float32((1+r)^(-1))
sigma_range = 4
gz = 19
gp = 29
gk = 37
lnz=collect(linspace(-sigma_range*sigma,sigma_range*sigma,gz))
z=exp(lnz)
gk_m = fld(gk,2)
# Need to add mu somewhere to k_ss
k_ss = (theta*(1-tau)/(r+delta))^(1/(1-theta))
k=cat(1,map(i->k_ss*((1-delta)^i),collect(1:gk_m)),map(i->k_ss/((1-delta)^i),collect(1:gk_m)))
insert!(k,gk_m+1,k_ss)
sort!(k)
p_bar=p_bar_k_ss*k_ss
p = collect(linspace(-p_bar/2,p_bar,gp))
#Tauchen
N = length(z)
Z = zeros(N,1)
Zprob = zeros(Float32,N,N)
Z[N] = lnz[length(z)]
Z[1] = lnz[1]
zstep = (Z[N] - Z[1]) / (N - 1)
for i=2:(N-1)
Z[i] = Z[1] + zstep * (i - 1)
end
for a = 1 : N
for b = 1 : N
if b == 1
Zprob[a,b] = 0.5*erfc(-((Z[1] - mu - rho * Z[a] + zstep / 2) / sigma)/sqrt(2))
elseif b == N
Zprob[a,b] = 1 - 0.5*erfc(-((Z[N] - mu - rho * Z[a] - zstep / 2) / sigma)/sqrt(2))
else
Zprob[a,b] = 0.5*erfc(-((Z[b] - mu - rho * Z[a] + zstep / 2) / sigma)/sqrt(2)) -
0.5*erfc(-((Z[b] - mu - rho * Z[a] - zstep / 2) / sigma)/sqrt(2))
end
end
end
# Collecting tauchen results in a 2 element array of linspace and array; [2] gets array
# Zprob=collect(tauchen(gz, rho, sigma, mu, sigma_range))[2]
Zcumprob=zeros(Float32,gz,gz)
# 2 in cumsum! denotes the 2nd dimension, i.e. columns
cumsum!(Zcumprob, Zprob,2)
gm = gk * gp
control=zeros(gm,2)
for i=1:gk
control[(1+gp*(i-1)):(gp*i),1]=fill(k[i],(gp,1))
control[(1+gp*(i-1)):(gp*i),2]=p
end
endog=copy(control)
E=Array(Float32,gm,gm,gz)
for h=1:gm
for m=1:gm
for j=1:gz
# set the nonzero net debt indicator
if endog[h,2]<0
p_ind=1
else
p_ind=0
end
# set the investment indicator
if (control[m,1]-(1-delta)*endog[h,1])!=0
i_ind=1
else
i_ind=0
end
E[m,h,j] = (1-tau)*z[j]*(endog[h,1]^theta) + control[m,2]-endog[h,2]*(1+r*(1-tau)) +
delta*endog[h,1]*tau-(control[m,1]-(1-delta)*endog[h,1]) -
(i_ind*gamma*endog[h,1]+endog[h,1]*(a_capital/2)*(((control[m,1]-(1-delta)*endog[h,1])/endog[h,1])^2)) +
s*endog[h,2]*p_ind
elem = E[m,h,j]
if E[m,h,j]<0
E[m,h,j]=elem+lambda1*elem-.5*lambda2*elem^2
else
E[m,h,j]=elem
end
end
end
end
function add_vecs!(gm::Int,r::Array{Float32},h::Int,j::Int,E::Array{Float32},
exp_v::Array{Float32},beta::Float32)
#inbounds #views for i=1:gm
r[i]=E[i,h,j] + beta*exp_v[i,j]
end
return r
end
function dynam_serial(E::Array{Float32},gm::Int,gz::Int,beta::Float32,Zprob::Array{Float32})
v = Array{Float32}(gm,gz)
fill!(v,E[cld(gm,2),cld(gm,2),cld(gz,2)])
Tv = Array{Float32}(gm,gz)
# Set parameters for the loop
convcrit = 0.0001 # chosen convergence criterion
diff = 1.00000 # arbitrary initial value greater than convcrit
iter=0
exp_v=Array{Float32}(gm,gz)
r=Array{Float32}(gm)
while diff>convcrit
A_mul_Bt!(exp_v,v,Zprob)
for h=1:gm
for j=1:gz
Tv[h,j]=findmax(add_vecs!(gm,r,h,j,E,exp_v,beta))[1]
end
end
diff = maximum(abs,Tv - v)
(v,Tv)=(Tv,v)
end
return v
end

Generate hex numbers based on percentage

I'm looking for a way to generate a gradual hexadecimal color based on a percentage with Ruby.
0% = #6da94a
50% = #decc30
100% = #ce2d4a
Then programmatically generate the hexadecimal values in between those.
So I might have something like percent_to_hex(10) and that would spit out whatever hexadecimal value is 10% along the gradual gradient between 0% (green) and 50% (yellow).
Actually there is a small mistake in tralston's answer.
(x + percent * 100 * (y - x)).round
should be changed to:
(x + percent / 100.0 * (y - x)).round
Also i.to_s(16) would be a problem if you have 0 (255), as you can get a result like "ff0ff". I would recommend using "%02x" % i instead.
Here is the complete example:
def percent_to_hex(percent, start, stop)
colors = [start,stop].map do |c|
c.scan(/../).map { |s| s.to_i(16) }
end
colors_int = colors.transpose.map do |x,y|
(x + percent / 100.0 * (y - x)).round
end
colors_int.map { |i| "%02x" % i }.join("")
end
Not a very polished method, but here's a good start:
# Example input: percent_to_hex(25, "abcdef", "ffffff") => "c0daf3"
def percent_to_hex(percent, start, stop)
colors = [start,stop].map do |c|
c.scan(/../).map { |s| s.to_i(16) }
end
colors_int = colors.transpose.map do |x,y|
(x + percent * 100 * (y - x)).round
end
colors_int.map { |i| i.to_s(16) }.join("")
end
Of course if you could customize it further to add or remove the leading "#" of the hex color code, etc.

Algorithm for iterating over an outward spiral on a discrete 2D grid from the origin

For example, here is the shape of intended spiral (and each step of the iteration)
y
|
|
16 15 14 13 12
17 4 3 2 11
-- 18 5 0 1 10 --- x
19 6 7 8 9
20 21 22 23 24
|
|
Where the lines are the x and y axes.
Here would be the actual values the algorithm would "return" with each iteration (the coordinates of the points):
[0,0],
[1,0], [1,1], [0,1], [-1,1], [-1,0], [-1,-1], [0,-1], [1,-1],
[2,-1], [2,0], [2,1], [2,2], [1,2], [0,2], [-1,2], [-2,2], [-2,1], [-2,0]..
etc.
I've tried searching, but I'm not exactly sure what to search for exactly, and what searches I've tried have come up with dead ends.
I'm not even sure where to start, other than something messy and inelegant and ad-hoc, like creating/coding a new spiral for each layer.
Can anyone help me get started?
Also, is there a way that can easily switch between clockwise and counter-clockwise (the orientation), and which direction to "start" the spiral from? (the rotation)
Also, is there a way to do this recursively?
My application
I have a sparse grid filled with data points, and I want to add a new data point to the grid, and have it be "as close as possible" to a given other point.
To do that, I'll call grid.find_closest_available_point_to(point), which will iterate over the spiral given above and return the first position that is empty and available.
So first, it'll check point+[0,0] (just for completeness's sake). Then it'll check point+[1,0]. Then it'll check point+[1,1]. Then point+[0,1], etc. And return the first one for which the position in the grid is empty (or not occupied already by a data point).
There is no upper bound to grid size.
There's nothing wrong with direct, "ad-hoc" solution. It can be clean enough too.
Just notice that spiral is built from segments. And you can get next segment from current one rotating it by 90 degrees. And each two rotations, length of segment grows by 1.
edit Illustration, those segments numbered
... 11 10
7 7 7 7 6 10
8 3 3 2 6 10
8 4 . 1 6 10
8 4 5 5 5 10
8 9 9 9 9 9
// (di, dj) is a vector - direction in which we move right now
int di = 1;
int dj = 0;
// length of current segment
int segment_length = 1;
// current position (i, j) and how much of current segment we passed
int i = 0;
int j = 0;
int segment_passed = 0;
for (int k = 0; k < NUMBER_OF_POINTS; ++k) {
// make a step, add 'direction' vector (di, dj) to current position (i, j)
i += di;
j += dj;
++segment_passed;
System.out.println(i + " " + j);
if (segment_passed == segment_length) {
// done with current segment
segment_passed = 0;
// 'rotate' directions
int buffer = di;
di = -dj;
dj = buffer;
// increase segment length if necessary
if (dj == 0) {
++segment_length;
}
}
}
To change original direction, look at original values of di and dj. To switch rotation to clockwise, see how those values are modified.
Here's a stab at it in C++, a stateful iterator.
class SpiralOut{
protected:
unsigned layer;
unsigned leg;
public:
int x, y; //read these as output from next, do not modify.
SpiralOut():layer(1),leg(0),x(0),y(0){}
void goNext(){
switch(leg){
case 0: ++x; if(x == layer) ++leg; break;
case 1: ++y; if(y == layer) ++leg; break;
case 2: --x; if(-x == layer) ++leg; break;
case 3: --y; if(-y == layer){ leg = 0; ++layer; } break;
}
}
};
Should be about as efficient as it gets.
This is the javascript solution based on the answer at
Looping in a spiral
var x = 0,
y = 0,
delta = [0, -1],
// spiral width
width = 6,
// spiral height
height = 6;
for (i = Math.pow(Math.max(width, height), 2); i>0; i--) {
if ((-width/2 < x && x <= width/2)
&& (-height/2 < y && y <= height/2)) {
console.debug('POINT', x, y);
}
if (x === y
|| (x < 0 && x === -y)
|| (x > 0 && x === 1-y)){
// change direction
delta = [-delta[1], delta[0]]
}
x += delta[0];
y += delta[1];
}
fiddle: http://jsfiddle.net/N9gEC/18/
This problem is best understood by analyzing how changes coordinates of spiral corners. Consider this table of first 8 spiral corners (excluding origin):
x,y | dx,dy | k-th corner | N | Sign |
___________________________________________
1,0 | 1,0 | 1 | 1 | +
1,1 | 0,1 | 2 | 1 | +
-1,1 | -2,0 | 3 | 2 | -
-1,-1 | 0,-2 | 4 | 2 | -
2,-1 | 3,0 | 5 | 3 | +
2,2 | 0,3 | 6 | 3 | +
-2,2 | -4,0 | 7 | 4 | -
-2,-2 | 0,-4 | 8 | 4 | -
By looking at this table we can calculate X,Y of k-th corner given X,Y of (k-1) corner:
N = INT((1+k)/2)
Sign = | +1 when N is Odd
| -1 when N is Even
[dx,dy] = | [N*Sign,0] when k is Odd
| [0,N*Sign] when k is Even
[X(k),Y(k)] = [X(k-1)+dx,Y(k-1)+dy]
Now when you know coordinates of k and k+1 spiral corner you can get all data points in between k and k+1 by simply adding 1 or -1 to x or y of last point.
Thats it.
good luck.
I would solve it using some math. Here is Ruby code (with input and output):
(0..($*.pop.to_i)).each do |i|
j = Math.sqrt(i).round
k = (j ** 2 - i).abs - j
p = [k, -k].map {|l| (l + j ** 2 - i - (j % 2)) * 0.5 * (-1) ** j}.map(&:to_i)
puts "p => #{p[0]}, #{p[1]}"
end
E.g.
$ ruby spiral.rb 10
p => 0, 0
p => 1, 0
p => 1, 1
p => 0, 1
p => -1, 1
p => -1, 0
p => -1, -1
p => 0, -1
p => 1, -1
p => 2, -1
p => 2, 0
And golfed version:
p (0..$*.pop.to_i).map{|i|j=Math.sqrt(i).round;k=(j**2-i).abs-j;[k,-k].map{|l|(l+j**2-i-j%2)*0.5*(-1)**j}.map(&:to_i)}
Edit
First try to approach the problem functionally. What do you need to know, at each step, to get to the next step?
Focus on plane's first diagonal x = y. k tells you how many steps you must take before touching it: negative values mean you have to move abs(k) steps vertically, while positive mean you have to move k steps horizontally.
Now focus on the length of the segment you're currently in (spiral's vertices - when the inclination of segments change - are considered as part of the "next" segment). It's 0 the first time, then 1 for the next two segments (= 2 points), then 2 for the next two segments (= 4 points), etc. It changes every two segments and each time the number of points part of that segments increase. That's what j is used for.
Accidentally, this can be used for getting another bit of information: (-1)**j is just a shorthand to "1 if you're decreasing some coordinate to get to this step; -1 if you're increasing" (Note that only one coordinate is changed at each step). Same holds for j%2, just replace 1 with 0 and -1 with 1 in this case. This mean they swap between two values: one for segments "heading" up or right and one for those going down or left.
This is a familiar reasoning, if you're used to functional programming: the rest is just a little bit of simple math.
It can be done in a fairly straightforward way using recursion. We just need some basic 2D vector math and tools for generating and mapping over (possibly infinite) sequences:
// 2D vectors
const add = ([x0, y0]) => ([x1, y1]) => [x0 + x1, y0 + y1];
const rotate = θ => ([x, y]) => [
Math.round(x * Math.cos(θ) - y * Math.sin(θ)),
Math.round(x * Math.sin(θ) + y * Math.cos(θ))
];
// Iterables
const fromGen = g => ({ [Symbol.iterator]: g });
const range = n => [...Array(n).keys()];
const map = f => it =>
fromGen(function*() {
for (const v of it) {
yield f(v);
}
});
And now we can express a spiral recursively by generating a flat line, plus a rotated (flat line, plus a rotated (flat line, plus a rotated ...)):
const spiralOut = i => {
const n = Math.floor(i / 2) + 1;
const leg = range(n).map(x => [x, 0]);
const transform = p => add([n, 0])(rotate(Math.PI / 2)(p));
return fromGen(function*() {
yield* leg;
yield* map(transform)(spiralOut(i + 1));
});
};
Which produces an infinite list of the coordinates you're interested in. Here's a sample of the contents:
const take = n => it =>
fromGen(function*() {
for (let v of it) {
if (--n < 0) break;
yield v;
}
});
const points = [...take(5)(spiralOut(0))];
console.log(points);
// => [[0,0],[1,0],[1,1],[0,1],[-1,1]]
You can also negate the rotation angle to go in the other direction, or play around with the transform and leg length to get more complex shapes.
For example, the same technique works for inward spirals as well. It's just a slightly different transform, and a slightly different scheme for changing the length of the leg:
const empty = [];
const append = it1 => it2 =>
fromGen(function*() {
yield* it1;
yield* it2;
});
const spiralIn = ([w, h]) => {
const leg = range(w).map(x => [x, 0]);
const transform = p => add([w - 1, 1])(rotate(Math.PI / 2)(p));
return w * h === 0
? empty
: append(leg)(
fromGen(function*() {
yield* map(transform)(spiralIn([h - 1, w]));
})
);
};
Which produces (this spiral is finite, so we don't need to take some arbitrary number):
const points = [...spiralIn([3, 3])];
console.log(points);
// => [[0,0],[1,0],[2,0],[2,1],[2,2],[1,2],[0,2],[0,1],[1,1]]
Here's the whole thing together as a live snippet if you want play around with it:
// 2D vectors
const add = ([x0, y0]) => ([x1, y1]) => [x0 + x1, y0 + y1];
const rotate = θ => ([x, y]) => [
Math.round(x * Math.cos(θ) - y * Math.sin(θ)),
Math.round(x * Math.sin(θ) + y * Math.cos(θ))
];
// Iterables
const fromGen = g => ({ [Symbol.iterator]: g });
const range = n => [...Array(n).keys()];
const map = f => it =>
fromGen(function*() {
for (const v of it) {
yield f(v);
}
});
const take = n => it =>
fromGen(function*() {
for (let v of it) {
if (--n < 0) break;
yield v;
}
});
const empty = [];
const append = it1 => it2 =>
fromGen(function*() {
yield* it1;
yield* it2;
});
// Outward spiral
const spiralOut = i => {
const n = Math.floor(i / 2) + 1;
const leg = range(n).map(x => [x, 0]);
const transform = p => add([n, 0])(rotate(Math.PI / 2)(p));
return fromGen(function*() {
yield* leg;
yield* map(transform)(spiralOut(i + 1));
});
};
// Test
{
const points = [...take(5)(spiralOut(0))];
console.log(JSON.stringify(points));
}
// Inward spiral
const spiralIn = ([w, h]) => {
const leg = range(w).map(x => [x, 0]);
const transform = p => add([w - 1, 1])(rotate(Math.PI / 2)(p));
return w * h === 0
? empty
: append(leg)(
fromGen(function*() {
yield* map(transform)(spiralIn([h - 1, w]));
})
);
};
// Test
{
const points = [...spiralIn([3, 3])];
console.log(JSON.stringify(points));
}
Here is a Python implementation based on the answer by #mako.
def spiral_iterator(iteration_limit=999):
x = 0
y = 0
layer = 1
leg = 0
iteration = 0
yield 0, 0
while iteration < iteration_limit:
iteration += 1
if leg == 0:
x += 1
if (x == layer):
leg += 1
elif leg == 1:
y += 1
if (y == layer):
leg += 1
elif leg == 2:
x -= 1
if -x == layer:
leg += 1
elif leg == 3:
y -= 1
if -y == layer:
leg = 0
layer += 1
yield x, y
Running this code:
for x, y in spiral_iterator(10):
print(x, y)
Yields:
0 0
1 0
1 1
0 1
-1 1
-1 0
-1 -1
0 -1
1 -1
2 -1
2 0
Try searching for either parametric or polar equations. Both are suitable to plotting spirally things. Here's a page that has plenty of examples, with pictures (and equations). It should give you some more ideas of what to look for.
I've done pretty much the same thin as a training exercise, with some differences in the output and the spiral orientation, and with an extra requirement, that the functions spatial complexity has to be O(1).
After think for a while I came to the idea that by knowing where does the spiral start and the position I was calculating the value for, I could simplify the problem by subtracting all the complete "circles" of the spiral, and then just calculate a simpler value.
Here is my implementation of that algorithm in ruby:
def print_spiral(n)
(0...n).each do |y|
(0...n).each do |x|
printf("%02d ", get_value(x, y, n))
end
print "\n"
end
end
def distance_to_border(x, y, n)
[x, y, n - 1 - x, n - 1 - y].min
end
def get_value(x, y, n)
dist = distance_to_border(x, y, n)
initial = n * n - 1
(0...dist).each do |i|
initial -= 2 * (n - 2 * i) + 2 * (n - 2 * i - 2)
end
x -= dist
y -= dist
n -= dist * 2
if y == 0 then
initial - x # If we are in the upper row
elsif y == n - 1 then
initial - n - (n - 2) - ((n - 1) - x) # If we are in the lower row
elsif x == n - 1 then
initial - n - y + 1# If we are in the right column
else
initial - 2 * n - (n - 2) - ((n - 1) - y - 1) # If we are in the left column
end
end
print_spiral 5
This is not exactly the thing you asked for, but I believe it'll help you to think your problem
I had a similar problem, but I didn't want to loop over the entire spiral each time to find the next new coordinate. The requirement is that you know your last coordinate.
Here is what I came up with with a lot of reading up on the other solutions:
function getNextCoord(coord) {
// required info
var x = coord.x,
y = coord.y,
level = Math.max(Math.abs(x), Math.abs(y));
delta = {x:0, y:0};
// calculate current direction (start up)
if (-x === level)
delta.y = 1; // going up
else if (y === level)
delta.x = 1; // going right
else if (x === level)
delta.y = -1; // going down
else if (-y === level)
delta.x = -1; // going left
// check if we need to turn down or left
if (x > 0 && (x === y || x === -y)) {
// change direction (clockwise)
delta = {x: delta.y,
y: -delta.x};
}
// move to next coordinate
x += delta.x;
y += delta.y;
return {x: x,
y: y};
}
coord = {x: 0, y: 0}
for (i = 0; i < 40; i++) {
console.log('['+ coord.x +', ' + coord.y + ']');
coord = getNextCoord(coord);
}
Still not sure if it is the most elegant solution. Perhaps some elegant maths could remove some of the if statements. Some limitations would be needing some modification to change spiral direction, doesn't take into account non-square spirals and can't spiral around a fixed coordinate.
I have an algorithm in java that outputs a similar output to yours, except that it prioritizes the number on the right, then the number on the left.
public static String[] rationals(int amount){
String[] numberList=new String[amount];
int currentNumberLeft=0;
int newNumberLeft=0;
int currentNumberRight=0;
int newNumberRight=0;
int state=1;
numberList[0]="("+newNumberLeft+","+newNumberRight+")";
boolean direction=false;
for(int count=1;count<amount;count++){
if(direction==true&&newNumberLeft==state){direction=false;state=(state<=0?(-state)+1:-state);}
else if(direction==false&&newNumberRight==state){direction=true;}
if(direction){newNumberLeft=currentNumberLeft+sign(state);}else{newNumberRight=currentNumberRight+sign(state);}
currentNumberLeft=newNumberLeft;
currentNumberRight=newNumberRight;
numberList[count]="("+newNumberLeft+","+newNumberRight+")";
}
return numberList;
}
Here's the algorithm. It rotates clockwise, but could easily rotate anticlockwise, with a few alterations. I made it in just under an hour.
// spiral_get_value(x,y);
sx = argument0;
sy = argument1;
a = max(sqrt(sqr(sx)),sqrt(sqr(sy)));
c = -b;
d = (b*2)+1;
us = (sy==c and sx !=c);
rs = (sx==b and sy !=c);
bs = (sy==b and sx !=b);
ls = (sx==c and sy !=b);
ra = rs*((b)*2);
ba = bs*((b)*4);
la = ls*((b)*6);
ax = (us*sx)+(bs*-sx);
ay = (rs*sy)+(ls*-sy);
add = ra+ba+la+ax+ay;
value = add+sqr(d-2)+b;
return(value);`
It will handle any x / y values (infinite).
It's written in GML (Game Maker Language), but the actual logic is sound in any programming language.
The single line algorithm only has 2 variables (sx and sy) for the x and y inputs. I basically expanded brackets, a lot. It makes it easier for you to paste it into notepad and change 'sx' for your x argument / variable name and 'sy' to your y argument / variable name.
`// spiral_get_value(x,y);
sx = argument0;
sy = argument1;
value = ((((sx==max(sqrt(sqr(sx)),sqrt(sqr(sy))) and sy !=(-1*max(sqrt(sqr(sx)),sqrt(sqr(sy))))))*((max(sqrt(sqr(sx)),sqrt(sqr(sy))))*2))+(((sy==max(sqrt(sqr(sx)),sqrt(sqr(sy))) and sx !=max(sqrt(sqr(sx)),sqrt(sqr(sy)))))*((max(sqrt(sqr(sx)),sqrt(sqr(sy))))*4))+(((sx==(-1*max(sqrt(sqr(sx)),sqrt(sqr(sy)))) and sy !=max(sqrt(sqr(sx)),sqrt(sqr(sy)))))*((max(sqrt(sqr(sx)),sqrt(sqr(sy))))*6))+((((sy==(-1*max(sqrt(sqr(sx)),sqrt(sqr(sy)))) and sx !=(-1*max(sqrt(sqr(sx)),sqrt(sqr(sy))))))*sx)+(((sy==max(sqrt(sqr(sx)),sqrt(sqr(sy))) and sx !=max(sqrt(sqr(sx)),sqrt(sqr(sy)))))*-sx))+(((sx==max(sqrt(sqr(sx)),sqrt(sqr(sy))) and sy !=(-1*max(sqrt(sqr(sx)),sqrt(sqr(sy))))))*sy)+(((sx==(-1*max(sqrt(sqr(sx)),sqrt(sqr(sy)))) and sy !=max(sqrt(sqr(sx)),sqrt(sqr(sy)))))*-sy))+sqr(((max(sqrt(sqr(sx)),sqrt(sqr(sy)))*2)+1)-2)+max(sqrt(sqr(sx)),sqrt(sqr(sy)));
return(value);`
I know the reply is awfully late :D but i hope it helps future visitors.

Resources