I have a set of pre-declared values to set specific rotations for an object.
local rotations = {900,-900}
And want my spawn function for the blocks to randomly pick one or the other from this function:
local blocks = {}
timerSrc = timer.performWithDelay(1200, createBlock, -1)
function createBlock(event)
b = display.newImageRect("images/block8.png", 20, 150)
b.x = 500
b.y = math.random(100,250)
b.name = 'block'
physics.addBody(b, "static")
transition.to( b, { rotation = math.random(rotations), time = math.random(2700,3700)} )
blocks:insert(b)
end
When I use:
rotation = math.random(-900,900)
it just chooses any values between the 2 numbers rather than 1 or the other. How can I do this correctly ?
If m is an integer value, math.random(m) returns integers in range [1, m] randomly. So math.random(2) returns integers 1 or 2 randomly.
To generate random numbers either 900 or -900, use:
rotation = math.random(2) == 1 and 900 or -900
Related
I need a function that finds a variable amount of numbers, which together must add up to a certain value. In this case it is 8.
The numbers which can be added together are predefined in a table, to make things easier.
Current approach: Shuffle the table using a small algorithm, add first X values together, if they don't add up to 8, start over (including shuffling again) until the first X values add up to 8.
My code does work, just 2 problems: It takes a long time to process (obviously) and it can cause a stack overflow error if I don't add a cooldown.
Code can be dirty, it's not for a live production. Also im only an intermediate lua developer at best...
function sleep (a) -- random sleep function I found
local sec = tonumber(os.clock() + a);
while (os.clock() < sec) do
end
end
function shuffle(tbl) -- random shuffle function I found
for i = #tbl, 2, -1 do
math.randomseed( os.time() )
math.random();math.random();math.random();math.random();
local j = math.random(i)
tbl[i], tbl[j] = tbl[j], tbl[i]
end
return tbl
end
local times = {
0.5,
1.0,
1.5,
2.0,
2.5,
3.0,
3.5,
4.0
}
local timeunits = {} --refer to line 49, I did not want to do it like that...
function nnumbersto8(amount)
local sum = 0
local numbs = {}
times = shuffle(times) --reshuffle the set
for i = 1,amount,1 do --add first x values together
sum = sum + times[i]
numbs[i] = times[i]
end
if sum ~= 8 then sleep(0.1) nnumbersto8(amount) return end --if they are not 8, repeat process with cooldown to avoid stack overflow
--return numbs -- This doesn't work for some reason, nothing gets returned outside the function
timeunits = numbs
end
nnumbersto8(5) -- manual run it for now
print(unpack(timeunits))
There must be a simpler way, right?
Thanks in advance, any help is appreciated!
Here is a method that will work for large numbers of elements, and will pick a random solution with theoretically even likelihood for each.
function solution_node (value, count, remainder)
local node = {}
node.value = value
node.count = count
node.remainder = remainder
return node
end
function choose_solutions (node1, node2)
if node1 == nil then
return node2
elseif node2 == nil then
return node1
else
-- Make a random choice of which solution to pick.
if node1.count < math.random(node1.count + node2.count) then
node2.count = node1.count + node2.count
return node2
else
node1.count = node1.count + node2.count
return node1
end
end
end
function decode_solution (node)
if node == nil then
return nil
end
answer = {}
while node.value ~= nil do
table.insert(answer, node.value)
-- This causes the solution to be randomly shuffled.
local i = math.random(#answer)
answer[#answer], answer[i] = answer[i], answer[#answer]
node = node.remainder
end
return answer
end
function random_sum(tbl, count, target)
local choices = {}
-- Normally arrays are not 0-based in Lua but this is very convenient.
for j = 0,count do
choices[j] = {}
end
-- Make sure that the empty set is there.
choices[0][0.0] = solution_node(nil, 1, nil)
for i = 1,#tbl do
for j = count,1,-1 do
for this_sum, node in pairs(choices[j-1]) do
local next_sum = this_sum + tbl[i]
local next_node = solution_node(tbl[i], node.count, node)
-- Try adding this value in to a solution.
if next_sum <= target then
choices[j][next_sum] = choose_solutions(next_node, choices[j][next_sum])
end
end
end
end
return decode_solution(choices[count][target])
end
local times = {
0.2,
0.3,
0.5,
1.0,
1.2,
1.3,
1.5,
2.0,
2.5,
3.0,
3.5,
4.0
}
math.randomseed( os.time() )
local result = random_sum(times, 5, 8.0)
print("answer")
for k, v in pairs(result) do print(v) end
Sorry for my code. I haven't coded in Lua for a few years.
This is the subset sum problem with an extra restriction on the number of elements you are allowed to choose.
The solution is to use Dynamic Programming similar to regular Subset Sum, but add an extra variable that indicates how many items you have used.
This should go something among the lines of:
Failing stop clauses:
DP[-1][x][n] = false, for all x,n>0 // out of elements
DP[i][-1][n] = false, for all i,n>0 // exceeded X items
DP[i][x][n] = false n < 0 // Passed the sum limit. This is an optimization only if all elements are non negative.
Successful stop clause:
DP[i][0][0] = true for all i >= 0
Recursive formula:
DP[i][x][n] = DP[i-1][x][n] OR DP[i-1][x-1][n-item[i]] // Watch for n<item[i] case here.
^ ^
Did not take the item Used the item
There are no solutions for 1, 2 and for values greater than 5, so the function only accepts 3, 4 and 5.
Here we are doing a shallow copy of the times table then we get a random index from the copy and begin searching for the solution, removing values we use as we go.
local times = {
0.5,
1.0,
1.5,
2.0,
2.5,
3.0,
3.5,
4.0
}
function nNumbersTo8(amount)
if amount < 3 or amount > 5 then
return {}
end
local sum = 0
local numbers = {}
local set = {table.unpack(times)}
for i = 1, amount - 1, 1 do
local index = math.random(#set)
local value = set[index]
if not (8 < (sum + value)) then
sum = sum + value
table.insert(numbers, value)
table.remove(set, index)
else
break
end
end
local reminder = 8 - sum
for _,v in ipairs(set)do
if v == reminder then
sum = sum + v
table.insert(numbers, v)
break
end
end
if #numbers == amount then
return numbers
else
return nNumbersTo8(amount)
end
end
for i=1,100 do
print(table.unpack(nNumbersTo8(5)))
end
Example response:
1.5 0.5 3 2 1
3 0.5 1.5 1 2
2 3 1.5 0.5 1
3 2 1.5 1 0.5
0.5 1 2 3 1.5
Let's say I have two sets of coordinates. Set A is the ground truth coordinates and set B is the newly generated coordinates.
I am classifying the following way:
True positives if the coordinate in set A is at least within 5 pixels of a coordinate in B.
False negative for all the coordinates in set A that do not find matches with any coordinates in set B.
False positive for all the coordinates in set B that do find matches with any coordinates in set A.
The sets do not correspond. By that I mean, the first coordinate in set A doesn't have any relevance with the first coordinate in set B.
Here is my code:
clear;
w = warning ('off','all');
coordA = dir('./GT*.txt');
coordB = dir('./O*.txt');
for i =1:length(coordA)
TP = [];
FP = [];
FN = [];
%read coordinate files
fir = fopen(coordA(i).name, 'r');
disp(coordA(i).name);
A = textscan(fir, '%d %d\n');
fclose(fir);
disp(coordB(i).name);
sec = fopen(coordB(i).name, 'r');
B = textscan(fir, '%d, %d\n');
fclose(sec);
A_x = A{1};
A_y = A{2};
B_x = B{1};
B_y = B{2};
for j = 1:length(A_x)
flag = 1; %this flag indicates false negatives
for k = 1:length(B_x)
X = [A_x(j), A_y(j); B_x(k), B_y(k)];
d = pdist(X);
if(d <= 5)
flag = 0; %Ax and Ay
%the problem is here---------
TP = [TP [B_x(k) B_y(k)]];
B_x(k) = 0;
B_y(k) = 0;
end
end
if(flag)
FN = [FN [A_x(j) A_y(j)]];
end
end
for b = find(B_x)
FP = [FP [B_x(b) B_y(b)]];
end
end
The problem(please note the comments in the code and example below) I am facing is the following. Let's say there are two coordinates in set A that are really close to each other. When I go to check for TPs in set B and I find a coordinate that's within 5 pixels, I mark it as true positive then remove that coordinate from set B. However, let's say I'm trying to check for the other nearby coordinate from set A. Well, it will be marked as a false negative since I removed a close by coordinate in set B when checking for a different coordinate.
I thought of not removing coordinates in set B even when I find a true positive, but then how would I find false positives?
I did this in Matlab, but any language is fine with me.
Example coordinates:
A:
250 500
251 500
B:
250 501
The second coordinate should also be considered as true positive, but its being considered as false negative.
By altering your code, I believe the following part should do what you are looking for. Basically, instead of removing entries, you can just use logical indexing:
clear;
w = warning ('off','all');
coordA = dir('./GT*.txt');
coordB = dir('./O*.txt');
radius = 5;
for i =1:length(coordA)
% read coordinate files
fir = fopen(coordA(i).name, 'r');
disp(coordA(i).name);
A = textscan(fir, '%d %d\n');
fclose(fir);
disp(coordB(i).name);
sec = fopen(coordB(i).name, 'r');
B = textscan(fir, '%d, %d\n');
fclose(sec);
A_x = A{1};
A_y = A{2};
B_x = B{1};
B_y = B{2};
% Initialize logical arrays to reflect the
% Status of each entry
TP = zeros(length(A_x),1); % no entry of A is considered true positive
FN = ones(length(A_x),1); % all entries of A are considered false negative
FP = ones(length(B_x),1); % all entries of B are considered false positive
for ij = 1:length(A_x)
for ijk = 1:length(B_x)
X = [A_x(ij), A_y(ij); B_x(ijk), B_y(ijk)];
d = pdist(X)
if (d <= radius)
TP(ij) = 1; % just found a true positive
FP(ijk) = 0;% no more a false positive
end
end
end
% Obtain the lists containing the appropriate values
% For true positive, just use logical indexing and TP array
True_Pos = [A_x(logical(TP))', A_y(logical(TP))'];
% For false negative, remove TP from FN
False_Neg = [A_x(logical(FN-TP))', A_y(logical(FN-TP))'];
% For false positive, whatever remained switched on in FP
False_Pos = [B_x(logical(FP))', B_y(logical(FP))'];
end
There are other approaches if you do need to remove entries (see my comment above). Moreover, there is a more clean way to code it but I tried to be explicit and follow your implementation.
How can I sort 2 lists y location ( map tiles and people ) and draw them in order dependent of y. 2 lists I want to use:
map = {}
map.y = {60,10,40,80}
map.t = {0,0,1,1} -- type
people = {}
people.y = {0,100}
people.t = {0,1} -- type
I can currently sort and draw a single list of hero and boxes.
Sort / draw code:
box1 = love.graphics.newImage("box1.png")
box2 = love.graphics.newImage("box2.png")
box3 = love.graphics.newImage("box3.png")
hero = love.graphics.newImage("hero.png")
object = {
x = {0, 50,100,200},
y = {0,200, 50,100},
g = {0,1,2,3}
}
function sortIndex(item)
local i
local id = {} -- id list
for i = 1, #item.x do -- Fill id list (1 to length)
id[i] = i
end
-- print( unpack(id) ) -- Check before
table.sort(id,sortY)-- Sort list
-- print( unpack(id) ) -- Check after
item.sort = id -- List added to object.sort
-- Sort id, using item values
function sortY(a,b)
return item.y[a] < item.y[b]
end
end
function drawObject()
local i,v, g,x,y
for i = 1, #object.x do
v = object.sort[i] -- Draw in order
x = object.x[v]
y = object.y[v]
g = object.g[v]
if g == 0 then g = hero -- set to an image value
elseif g == 1 then g = box1
elseif g == 2 then g = box2
elseif g == 3 then g = box3
end
love.graphics.draw(g,x,y,0,7,7)
end
end
Update sort:
sortIndex(object)
My function sorts an id list comparing a y location list. The id is used to draw objects in order dependent of their y. How can I sort 2 id lists together comparing 2 y location lists, then draw them in order?
Maybe when drawing, switch from map tiles to people dependent on y, but I don't know how.
Might be related to your previous question a lot: Returning A Sorted List's Index in Lua
I assume if your height can be 1,2 and 3 (with 1 being on the top), you first want to render all tiles at Y1, then all people at Y1, then Y2 and Y3. To do that, you'll have to make a combined list and sort that:
map = {}
map.y = {60,10,40,80}
map.t = {0,0,1,1} -- type
people = {}
people.y = {0,100}
people.t = {0,1} -- type
local all = {}
local map_y = map.y
local offset = #map_y
local people_y = people.y
-- Fill the list with map tiles
for i=1,offset do
all[i] = {1,i,map_y[i]} --{type,index,y}
end
-- Fill the list with people
for i=1,#people_y do
all[i+offset] = {2,i,people_y[i]}
end
-- Do the sorting
-- It works a bit like your previous question:
-- 'all' contains "references":
-- They tell us is it's from map/people + the index
-- We sort the references using the third element in it:
-- The 'y' variable we put there during the first 2 loops
table.sort(all,function(a,b)
return a[3] < b[3]
end)
-- Printing example
-- The references are sorted using the 'y' field of your objects
-- With v[1] we know if it's from map/people
-- The v[2] tells us the index in that ^ table
-- The v[3] is the 'y'-field. No real need to remove it
for k,v in pairs(all) do
print(v[1] == 1 and "Map" or "Person",v[2],"with y being",v[3])
end
Output:
Person 1 with y being 0
Map 2 with y being 10
Map 3 with y being 40
Map 1 with y being 60
Map 4 with y being 80
Person 2 with y being 100
There are 2 things I want to add, that doesn't have anything to do with the question of my answer:
Maybe it would be easier if you have a table for each element.
Your people would be {0,0} and {100,1} which might be easier to manipulate.
If you prefer your stuff always sorted, you might want to use this: Sorted List. If you keep a sorted list of all your objects, you don't have to sort the list everytime you add/remove an element, or worse, each time you render. (depending if people move) This might help with performance if you're planning to have a lot of map/people objects. (Sorted List could be useful for your current data system, but also the {y=1,t=1} one)
function sortIndex(...)
sorted = {} -- global
local arrays_order = {}
for arr_index, array in ipairs{...} do
arrays_order[array] = arr_index
for index = 1, #array.y do
table.insert(sorted, {array = array, index = index})
end
end
table.sort(sorted,
function (a,b)
local arr1, arr2 = a.array, b.array
local ind1, ind2 = a.index, b.index
return arr1.y[ind1] < arr2.y[ind2] or
arr1.y[ind1] == arr2.y[ind2] and arrays_order[arr1] < arrays_order[arr2]
end)
end
function drawAll()
for _, elem_info in ipairs(sorted) do
local array = elem_info.array
local index = elem_info.index
local x = array.x[index]
local y = array.y[index]
if array == map then
-- draw a map tile with love.graphics.draw()
elseif array == people then
-- draw a human with love.graphics.draw()
end
end
end
sortIndex(map, people) -- to draw map tiles before people for the same y
I would like to split a rectangle in cells. In each cell it should be create a random coordinate (y, z).
The wide and height of the rectangle are known (initialW / initalH).
The size of the cells are calculated (dy / dz).
The numbers, in how many cells the rectangle to be part, are known. (numberCellsY / numberCellsZ)
Here my Code in Fortran to split the rectangle in Cells:
yRVEMin = 0.0
yRVEMax = initialW
dy = ( yRVEMax - yRVEMin ) / numberCellsY
zRVEMin = 0.0
zRVEMax = initialH
dz = ( zRVEMax - zRVEMin ) / numberCellsZ
do i = 1, numberCellsY
yMin(i) = (i-1)*dy
yMax(i) = i*dy
end do
do j = 1, numberCellsZ
zMin(j) = (j-1)*dz
zMax(j) = j*dz
end do
Now I would like to produce a random coordinate in each cell. The problem for me is, to store the coodinates in an array. It does not necessarily all be stored in one array, but as least as possible.
To fill the cells with coordinates it should start at the bottom left cell, go through the rows (y-direction), and after the last cell (numberCellsY) jump a column higher (z-dicrection) and start again by the first cell of the new row at left side. That should be made so long until a prescribed number (nfibers) is reached.
Here a deplorable try to do it:
call random_seed
l = 0
do k = 1 , nfibers
if (l < numberCellsY) then
l = l + 1
else
l = 1
end if
call random_number(y)
fiberCoordY(k) = yMin(l) + y * (yMax(l) - yMin(l))
end do
n = 0
do m = 1 , nfibers
if (n < numberCellsZ) then
n = n + 1
else
n = 1
end if
call random_number(z)
fiberCoordZ(m) = zMin(n) + z * (zMax(n) - zMin(n))
end do
The output is not what I want! fiberCoordZ should be stay on (zMin(1) / zMax(1) as long as numberCellsY-steps are reached.
The output for following settings:
nfibers = 9
numberCellsY = 3
numberCellsZ = 3
initialW = 9.0
initialH = 9.0
My random output for fiberCoordY is:
1.768946 3.362770 8.667685 1.898700 5.796713 8.770239 2.463412 3.546694 7.074708
and for fiberCoordZ is:
2.234807 5.213032 6.762228 2.948657 5.937295 8.649946 0.6795220 4.340364 8.352566
In this case the first 3 numbers of fiberCoordz should have a value between 0.0 and 3.0. Than number 4 - 6 a value between 3.0 and 6.0. And number 7 - 9 a value bewtween 6.0 - 9.0.
How can I solve this? If somebody has a solution with a better approach, please post it!
Thanks
Looking at
n = 0
do m = 1 , nfibers
if (n < numberCellsZ) then
n = n + 1
else
n = 1
end if
call random_number(z)
fiberCoordZ(m) = zMin(n) + z * (zMax(n) - zMin(n))
end do
we see that the z coordinate offset (the bottom cell boundary of interest) is being incremented inappropriately: for each consecutive nfibers/numberCellsZ coordinates n should be constant.
n should be incremented only every numberCellsY iterations, so perhaps a condition like
if (MOD(m, numberCellsY).eq.1) n=n+1
would be better.
Thanks francescalus! It works fine.
I added a little more for the case that nfibers > numberCellsY*numberCellsZ
n=0
do m = 1 , nfibers
if (MOD(m, numberCellsY).eq.1 .and. (n < numberCellsY)) then
n=n+1
end if
if (MOD(m, numberCellsY*numberCellsZ).eq.1 ) then
n = 1
end if
call random_number(z)
fiberCoordZ(m) = zMin(n) + z * (zMax(n) - zMin(n))
end do
There is a question on CrossValidated on how to use PyMC to fit two Normal distributions to data. The answer of Cam.Davidson.Pilon was to use a Bernoulli distribution to assign data to one of the two Normals:
size = 10
p = Uniform( "p", 0 , 1) #this is the fraction that come from mean1 vs mean2
ber = Bernoulli( "ber", p = p, size = size) # produces 1 with proportion p.
precision = Gamma('precision', alpha=0.1, beta=0.1)
mean1 = Normal( "mean1", 0, 0.001 )
mean2 = Normal( "mean2", 0, 0.001 )
#deterministic
def mean( ber = ber, mean1 = mean1, mean2 = mean2):
return ber*mean1 + (1-ber)*mean2
Now my question is: how to do it with three Normals?
Basically, the issue is that you can't use a Bernoulli distribution and 1-Bernoulli anymore. But how to do it then?
edit: With the CDP's suggestion, I wrote the following code:
import numpy as np
import pymc as mc
n = 3
ndata = 500
dd = mc.Dirichlet('dd', theta=(1,)*n)
category = mc.Categorical('category', p=dd, size=ndata)
precs = mc.Gamma('precs', alpha=0.1, beta=0.1, size=n)
means = mc.Normal('means', 0, 0.001, size=n)
#mc.deterministic
def mean(category=category, means=means):
return means[category]
#mc.deterministic
def prec(category=category, precs=precs):
return precs[category]
v = np.random.randint( 0, n, ndata)
data = (v==0)*(50+ np.random.randn(ndata)) \
+ (v==1)*(-50 + np.random.randn(ndata)) \
+ (v==2)*np.random.randn(ndata)
obs = mc.Normal('obs', mean, prec, value=data, observed = True)
model = mc.Model({'dd': dd,
'category': category,
'precs': precs,
'means': means,
'obs': obs})
The traces with the following sampling procedure look good as well. Solved!
mcmc = mc.MCMC( model )
mcmc.sample( 50000,0 )
mcmc.trace('means').gettrace()[-1,:]
there is a mc.Categorical object that does just this.
p = [0.2, 0.3, .5]
t = mc.Categorical('test', p )
t.random()
#array(2, dtype=int32)
It returns an int between 0 and len(p)-1. To model the 3 Normals, you make p a mc.Dirichlet object (it accepts a k length array as the hyperparameters; setting the values in the array to be the same is setting the prior probabilities to be equal). The rest of the model is nearly identical.
This is a generalization of the model I suggested above.
Update:
Okay, so instead of having different means, we can collapse them all into 1:
means = Normal( "means", 0, 0.001, size=3 )
...
#mc.deterministic
def mean(categorical=categorical, means = means):
return means[categorical]