I am currently working in a game spell system and I want to know if anyone knows a simple way to enlarge a matrix and also its values, almost like an image stretch.
I am using 2D matrices to represent the spell affected areas, so the below matrix represent the starting spell effect point and its effect area.
Example:
local area = {{0, 0, 1, 0, 0},
{0, 1, 1, 1, 0},
{1, 1, 3, 1, 1},
{0, 1, 1, 1, 0},
{0, 0, 1, 0, 0}}
Where:
3: Origin point (where the spell was cast)
1: Affected area relative to the origin point.
Taking this in consideration, I would like to develop a function to enlarge the matrix.
function matrix.enlarge(mtx, row, col) ... end
The abstraction and result of the following function taking the shown example of an area would be something like following:
local enlarged_matrix = matrix.enlarge(area, 2, 2)
matrix.print(enlarged_matrix)
--output
--local area = {{0, 0, 0, 1, 0, 0, 0},
-- {0, 0, 1, 1, 1, 0, 0},
-- {0, 1, 1, 1, 1, 1, 0},
-- {1, 1, 1, 3, 1, 1, 1},
-- {0, 1, 1, 1, 1, 1, 0},
-- {0, 0, 1, 1, 1, 0, 0},
-- {0, 0, 0, 1, 0, 0, 0}}
Several possibilities:
brute force: create new matrix, copy old into it:
function matrix.enlarge(area, horiz, vert)
local vertNow = #vert
local horizNow = #horiz
local newVert = vertNow + vert
local newHoriz = horizNow + horiz
-- create table of zeros
local newMatrix = {}
for i=1,newVert do
tt = {}
newMatrix[i] = tt
for j=1,newHoriz do
if i > vert/2 and i < vertNow + vert/2 and j > horiz/2 and j < horizNow + horiz/2 then
tt[j] = area[i][j]
else
tt[j] = 0
end
end
end
end
use formula: you have circular symmetry so just need radius, no need to store the value:
function distance(i,j)
return math.sqrt(i*i+j*j)
end
local dissip = 2 -- at a distance of "2", spell is e^(-0.5) of center
function getSpellStrength(dist) -- gaussian
return 3*math.exp(-math.pow(dist/dissip, 2))
end
val = getSpellStrength(distance(i,j))
If the actual computation of spell strength is heavy, and spread doesn't change often (say only when experience increases by a certain delta), then option 1 better. If spread changes quickly (say every time frame while spell taking effect), and spell strength as simple as gaussian, then option 2 better. For in-between cases it depends you'll have to try both. But #2 is simpler so I would favor it unless you can show that it is a performance bottleneck.
Also, the formula (option 2) is trivial to apply regardless of shape of room/area. If an enemy is at i1,j1, and caster at i2,j2, you can know immediately the spell strength at i1,j1 via distance(i1-i2,j1-j2), regardless of shape of room. You can also fairly easily combine effects of multiple spells, like a resistence spell by enemy (same distance formula).
If you really have to use matrix, and it must work for any shape, then probably this is best option:
scale the old matrix to a new matrix:
function enlarge(area, deltaX, deltaY)
sizeX = #(area[1])
sizeY = #area -- number of rows
scaleX = (sizeX + deltaX)/sizeX
scaleX = (sizeY + deltaY)/sizeY
newArea = {}
for iY=1, sizeY do
newRow = {}
newArea[iY] = newRow
fromY = round(iY/scaleY)
for jX=1, sizeX do
fromX = round(jX/scaleX)
if fromY < 1 or fromX < 1 or fromY > sizeY or fromX > sizeX then
val = 0
else
val = area[fromY][fromX]
end
newRow[jX] = val
end
end
return newArea
end
Here, you're basically creating a scaled version of the original (interpolation). WARNING: Not debugged, so you will have to massage this a bit (like there might be +-1 missing in a few places, you should declare your vars local, etc). And round() would be something like
function round(x)
return math.floor(num + 0.5)
end
But hopefully you can do the rest of the work :)
Related
I want to use the DateObject in Mathematica to calculate the difference in times between two cities.
How do I convert the DateObject and TimeObject output to numerical values so I can manipulate them and plot them?
You can obtain numerical values using DateList e.g.
d = Today
t = TimeObject[Now]
o = DateObject[d, t]
{dt, tm} = TakeDrop[DateList[o], 3]
DateString[o, {"DayName", ", ", "DayShort", " ", "MonthName"}]
By putting your code into comments you've made it very difficult to be certain what you have done, for example, it's no surprise that the expression
GeoPosition[Toronto]
is unevaluated and that the enclosing expressions do not do what you want them to do. Nevertheless, guessing at what you might be trying to do ...
If I execute the following:
sList = Table[Sunrise[Entity["City", {"Toronto", "Ontario", "Canada"}],
DateObject[{2022, 1, 9 + i, 0, 0, 0}]], {i, 0, 9}]
my Mathematica (v12.something on Mac) returns a list of 10 DateObjects, starting with
DateObject[{2022, 1, 9, 12, 50}, "Minute", "Gregorian", 0.]
And if I execute
AbsoluteTime /# sList
MMA returns a list of 10 absolute times.
Now, set
t1 = DateObject[{2022, 1, 9, 12, 50}, "Minute", "Gregorian", 0.]
and, using another city ...
t2 = Sunrise[Entity["City", {"Liverpool", "Liverpool", "UnitedKingdom"}],
DateObject[{2022, 1, 9, 0, 0, 0}]]
then
DateDifference[t1, t2]
returns
Quantity[-0.18472222222222223, "Days"]
You'll notice that I have not bothered with the time zone for the DateObject (irrelevant for calculating differences between cities) and I have not wrapped Toronto in GeoPosition, MMA is smart enough to not need that assistance.
The objective of the file is to calculate the numbers of hours of daylight in Toronto and Edmonton. First, create a counter called "daysElapsed"
daysElapsed=365;
Next, create a table of sunrises and sunsets. These are returned Date Objects / Quantities.
sunriseToList =
Table[Sunrise[Entity["City", {"Toronto", "Ontario", "Canada"}],
DateObject[{2022, 1, 1 + i, 0, 0, 0}]], {i, 0, daysElapsed}];
sunsetToList =
Table[Sunset[Entity["City", {"Toronto", "Ontario", "Canada"}],
DateObject[{2022, 1, 1 + i, 0, 0, 0}]], {i, 0, daysElapsed}];
Using the function, AbsoluteTime, convert the two lists of Date Objects into times in milliseconds. This allows you to manipulate the data easily.
sunrisenumTo = AbsoluteTime /# sunriseToList;
sunsetnumTo = AbsoluteTime /# sunsetToList;
Subtracting the time of sunrise from the time of sunset gives the total time of daylight.
hoursoflightTo = N[(sunsetnumTo - sunrisenumTo)/60/60];
Repeat the above process for the next city: Edmonton
sunriseEdList =
Table[Sunrise[Entity["City", {"Edmonton", "Alberta", "Canada"}],
DateObject[{2022, 1, 1 + i, 0, 0, 0}]], {i, 0, daysElapsed}];
sunsetEdList =
Table[Sunset[Entity["City", {"Edmonton", "Alberta", "Canada"}],
DateObject[{2022, 1, 1 + i, 0, 0, 0}]], {i, 0, daysElapsed}];
sunrisenumEd = AbsoluteTime /# sunriseEdList;
sunsetnumEd = AbsoluteTime /# sunsetEdList;
hoursoflightEd = N[(sunsetnumEd - sunrisenumEd)/60/60];
t = hoursoflightTo - hoursoflightEd;
The first plot below shows the difference in hours of sunlight. As Edmonton is in the far north, it gets less light in the winter and way more in the summer.
plotT = ListLinePlot[hoursoflightTo - hoursoflightEd]
Difference in hours of light between cities
This plots the hours of light for each city over 365 days.
ListPlot[{hoursoflightEd, hoursoflightTo},
ColorFunctionScaling -> True]
Hours of Light
How do I speed up the rank calculation of a sparse matrix in pure ruby?
I'm currently calculating the rank of a matrix (std lib) to determine the rigidity of a graph.
That means I have a sparse matrix of about 2 rows * 9 columns to about 300 rows * 300 columns.
That translates to times of several seconds to determine the rank of the matrix, which is very slow for a GUI application.
Because I use Sketchup I am bound to Ruby 2.0.0.
I'd like to avoid the hassle of setting up gcc on windows, so nmatrix is (I think) not a good option.
Edit:
Example matrix:
[[12, -21, 0, -12, 21, 0, 0, 0, 0],
[12, -7, -20, 0, 0, 0, -12, 7, 20],
[0, 0, 0, 0, 14, -20, 0, -14, 20]]
Edit2:
I am using integers instead of floats to speed it up considerably.
I have also added a fail fast mechanism earlier in the code in order to not call the slow rank function at all.
Edit3:
Part of the code
def rigid?(proto_matrix, nodes)
matrix_base = Array.new(proto_matrix.size) { |index|
# initialize the row with 0
arr = Array.new(nodes.size * 3, 0.to_int)
proto_row = proto_matrix[index]
# ids of the nodes in the graph
node_ids = proto_row.map { |hash| hash[:id] }
# set the values of both of the nodes' positions
[0, 1].each { |i|
vertex_index = vertices.find_index(node_ids[i])
# predetermined vector associated to the node
vec = proto_row[i][:vec]
arr[vertex_index * 3] = vec.x.to_int
arr[vertex_index * 3 + 1] = vec.y.to_int
arr[vertex_index * 3 + 2] = vec.z.to_int
}
arr
}
matrix = Matrix::rows(matrix_base, false)
rank = matrix.rank
# graph is rigid if the rank of the matrix is bigger or equal
# to the amount of node coordinates minus the degrees of freedom
# of the whole graph
rank >= nodes.size * 3 - 6
end
I am developing 4 in a row game. in this i am creating AI.
I have used same logic as Four in a row logic.
in my game 0 represents empty slot. 1 represents user slot and 2 for computer slot.
now i want to develop AI such that if user means '1' are three in a row then put 2 to its 4th row.
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 2, 2, 0, 0, 0],
[0, 1, 1, 1, 0, 0, 0]
i want to put 2 on last row 4th column after '1' like [0, 1, 1, 1, 2, 0, 0] and by creating AI then what to do?
The AI could be implemented by using the Minimax algorithm which can be found on Wikipedia under the following link:
http://en.wikipedia.org/wiki/Minimax
Basically, you need a function f to decide for a state of the game whether player 1 has won (value 1) or player 2 has won (value -1) or the game has not ended yet. If the game has not ended, all moves for the current player have to be evaluated by simulating them on the board and recursively calling F again, where the respective other player is active. The value of a possible move will be the maximum of the return values of F (if player 1 is the current player) or the minimum of the return values of F (if player 2 is the current player).
At least this is the rough idea; depending on the programming language used for implementation, the evaluation logic can be implemented independently from the specific game, such that the same code can play four-in-a-row or tic-tac-toe. Furthermore, evaluation can be stopped if a move of value 1 (for player 1) or -1 (for player 2) is found, which is also termed "pruning of the search tree".
use this part of code to prevent creating situations like 0,1,1,1,0 by user in all rows, it will return number of column that computer should play with that:
for(byte i=0;i<6;i++)
{
byte min = (byte) ((i * 7) + 1);
for(int j = 0;j<=2;j++) {
if (boardValues[min+j] == 1 && boardValues[min + j + 1] == 1 && boardValues[min - 1 + j] == 0 && boardValues[min +j + 2] == 0) {
if (i == 5) return (byte) ((min + j - 1)%7);
else if(boardValues[min - 1 + j + 7] != 0 && boardValues[min +j + 2 + 7] != 0)
return (byte) ((min + j - 1)%7);
}
}
}
boardValues is difined like this in my code:
public static byte[] boardValues = new byte[42];
It's maybe too late, but if someone is still interested to know, Here is a series of articles - http://blog.gamesolver.org/ .
It explains the concepts and logic, step by step to make a connect 4 resolver AI.
I have a image(png format) in hand. The lines that bound the ellipses (represent the nucleus) are over straight which are impractical. How could i extract the lines from the image and make them bent, and with the precondition that they still enclose the nucleus.
The following is the image:
After bending
EDIT: How can i translate the Dilation And Filter part in answer2 into Matlab language? I can't figure it out.
Ok, here is a way involving several randomization steps needed to get a "natural" non symmetrical appearance.
I am posting the actual code in Mathematica, just in case someone cares translating it to Matlab.
(* A preparatory step: get your image and clean it*)
i = Import#"http://i.stack.imgur.com/YENhB.png";
i1 = Image#Replace[ImageData[i], {0., 0., 0.} -> {1, 1, 1}, {2}];
i2 = ImageSubtract[i1, i];
i3 = Inpaint[i, i2]
(*Now reduce to a skeleton to get a somewhat random starting point.
The actual algorithm for this dilation does not matter, as far as we
get a random area slightly larger than the original elipses *)
id = Dilation[SkeletonTransform[
Dilation[SkeletonTransform#ColorNegate#Binarize#i3, 3]], 1]
(*Now the real random dilation loop*)
(*Init vars*)
p = Array[1 &, 70]; j = 1;
(*Store in w an image with a different color for each cluster, so we
can find edges between them*)
w = (w1 =
WatershedComponents[
GradientFilter[Binarize[id, .1], 1]]) /. {4 -> 0} // Colorize;
(*and loop ...*)
For[i = 1, i < 70, i++,
(*Select edges in w and dilate them with a random 3x3 kernel*)
ed = Dilation[EdgeDetect[w, 1], RandomInteger[{0, 1}, {3, 3}]];
(*The following is the core*)
p[[j++]] = w =
ImageFilter[ (* We apply a filter to the edges*)
(Switch[
Length[#1], (*Count the colors in a 3x3 neighborhood of each pixel*)
0, {{{0, 0, 0}, 0}}, (*If no colors, return bkg*)
1, #1, (*If one color, return it*)
_, {{{0, 0, 0}, 0}}])[[1, 1]] (*If more than one color, return bkg*)&#
Cases[Tally[Flatten[#1, 1]],
Except[{{0.`, 0.`, 0.`}, _}]] & (*But Don't count bkg pixels*),
w, 1,
Masking -> ed, (*apply only to edges*)
Interleaving -> True (*apply to all color chanels at once*)]
]
The result is:
Edit
For the Mathematica oriented reader, a functional code for the last loop could be easier (and shorter):
NestList[
ImageFilter[
If[Length[#1] == 1, #1[[1, 1]], {0, 0, 0}] &#
Cases[Tally[Flatten[#1, 1]], Except[{0.` {1, 1, 1}, _}]] & , #, 1,
Masking -> Dilation[EdgeDetect[#, 1], RandomInteger[{0, 1}, {3, 3}]],
Interleaving -> True ] &,
WatershedComponents#GradientFilter[Binarize[id,.1],1]/.{4-> 0}//Colorize,
5]
What you have as input is the Voronoi diagram. You can recalculate it using another distance function instead of the Euclidean one.
Here is an example in Mathematica using the Manhattan Distance (i3 is your input image without the lines):
ColorCombine[{Image[
WatershedComponents[
DistanceTransform[Binarize#i3,
DistanceFunction -> ManhattanDistance] ]], i3, i3}]
Edit
I am working with another algorithm (preliminary result). What do you think?
Here is what I came up with, it is not a direct translation of #belisarius code, but should be close enough..
%# read image (indexed image)
[I,map] = imread('http://i.stack.imgur.com/YENhB.png');
%# extract the blobs (binary image)
BW = (I==1);
%# skeletonization + dilation
BW = bwmorph(BW, 'skel', Inf);
BW = imdilate(BW, strel('square',2*1+1));
%# connected components
L = bwlabel(BW);
imshow(label2rgb(L))
%# filter 15x15 neighborhood
for i=1:13
L = nlfilter(L, [15 15], #myFilterFunc);
imshow( label2rgb(L) )
end
%# result
L(I==1) = 0; %# put blobs back
L(edge(L,'canny')) = 0; %# edges
imshow( label2rgb(L,#jet,[0 0 0]) )
myFilterFunc.m
function p = myFilterFunc(x)
if range(x(:)) == 0
p = x(1); %# if one color, return it
else
p = mode(x(x~=0)); %# else, return the most frequent color
end
end
The result:
and here is an animation of the process:
Currently I am working with some Mathematica code to do a Picard Iteration. The code itself works fine but I am trying to make it more efficient. I have had some success but am looking for suggestions. It may not be possible to speed it up anymore but I have run out of ideas and am hoping people with more experience with programming/Mathematica than me might be able to make some suggestions. I am only posting the Iteration itself but can supply additional information as needed.
The code below was edited to be a fully executable as requested
Also I changed it from a While to a Do loop to make testing easier as convergence is not required.
Clear["Global`*"]
ngrid = 2048;
delr = 4/100;
delk = \[Pi]/delr/ngrid;
rvalues = Table[(i - 1/2) delr, {i, 1, ngrid}];
kvalues = Table[(i - 1/2) delk, {i, 1, ngrid}];
wa[x_] := (19 + .5 x) Exp[-.7 x] + 1
wb[x_] := (19 + .1 x) Exp[-.2 x] + 1
wd = SetPrecision[
Table[{{wa[(i - 1/2) delk], 0}, {0, wb[(i - 1/2) delk]}}, {i, 1,
ngrid}], 26];
sigmaAA = 1;
hcloseAA = {};
i = 1;
While[(i - 1/2)*delr < sigmaAA, hcloseAA = Append[hcloseAA, -1]; i++]
hcloselenAA = Length[hcloseAA];
hcloseAB = hcloseAA;
hcloselenAB = hcloselenAA;
hcloseBB = hcloseAA;
hcloselenBB = hcloselenAA;
ccloseAA = {};
i = ngrid;
While[(i - 1/2)*delr >= sigmaAA, ccloseAA = Append[ccloseAA, 0]; i--]
ccloselenAA = Length[ccloseAA];
ccloselenAA = Length[ccloseAA];
ccloseAB = ccloseAA;
ccloselenAB = ccloselenAA;
ccloseBB = ccloseAA;
ccloselenBB = ccloselenAA;
na = 20;
nb = 20;
pa = 27/(1000 \[Pi]);
pb = 27/(1000 \[Pi]);
p = {{na pa, 0}, {0, nb pb}};
id = {{1, 0}, {0, 1}};
AFD = 1;
AFDList = {};
timelist = {};
gammainitial = Table[{{0, 0}, {0, 0}}, {ngrid}];
gammafirst = gammainitial;
step = 1;
tol = 10^-7;
old = 95/100;
new = 1 - old;
Do[
t = AbsoluteTime[];
extractgAA = Table[Extract[gammafirst, {i, 1, 1}], {i, hcloselenAA}];
extractgBB = Table[Extract[gammafirst, {i, 2, 2}], {i, hcloselenBB}];
extractgAB = Table[Extract[gammafirst, {i, 1, 2}], {i, hcloselenAB}];
csolutionAA = (Join[hcloseAA - extractgAA, ccloseAA]) rvalues;
csolutionBB = (Join[hcloseBB - extractgBB, ccloseBB]) rvalues;
csolutionAB = (Join[hcloseAB - extractgAB, ccloseAB]) rvalues;
chatAA = FourierDST[SetPrecision[csolutionAA, 32], 4];
chatBB = FourierDST[SetPrecision[csolutionBB, 32], 4];
chatAB = FourierDST[SetPrecision[csolutionAB, 32], 4];
chatmatrix =
2 \[Pi] delr Sqrt[2*ngrid]*
Transpose[{Transpose[{chatAA, chatAB}],
Transpose[{chatAB, chatBB}]}]/kvalues;
gammahat =
Table[(wd[[i]].chatmatrix[[i]].(Inverse[
id - p.wd[[i]].chatmatrix[[i]]]).wd[[i]] -
chatmatrix[[i]]) kvalues[[i]], {i, ngrid}];
gammaAA =
FourierDST[SetPrecision[Table[gammahat[[i, 1, 1]], {i, ngrid}], 32],
4];
gammaBB =
FourierDST[SetPrecision[Table[gammahat[[i, 2, 2]], {i, ngrid}], 32],
4];
gammaAB =
FourierDST[SetPrecision[Table[gammahat[[i, 1, 2]], {i, ngrid}], 32],
4];
gammasecond =
Transpose[{Transpose[{gammaAA, gammaAB}],
Transpose[{gammaAB, gammaBB}]}]/(rvalues 2 \[Pi] delr Sqrt[
2*ngrid]);
AFD = Sqrt[
1/ngrid Sum[((gammafirst[[i, 1, 1]] -
gammasecond[[i, 1, 1]])/(gammafirst[[i, 1, 1]] +
gammasecond[[i, 1, 1]]))^2 + ((gammafirst[[i, 2, 2]] -
gammasecond[[i, 2, 2]])/(gammafirst[[i, 2, 2]] +
gammasecond[[i, 2, 2]]))^2 + ((gammafirst[[i, 1, 2]] -
gammasecond[[i, 1, 2]])/(gammafirst[[i, 1, 2]] +
gammasecond[[i, 1, 2]]))^2 + ((gammafirst[[i, 2, 1]] -
gammasecond[[i, 2, 1]])/(gammafirst[[i, 2, 1]] +
gammasecond[[i, 2, 1]]))^2, {i, 1, ngrid}]];
gammafirst = old gammafirst + new gammasecond;
time2 = AbsoluteTime[] - t;
timelist = Append[timelist, time2], {1}]
Print["Mean time per calculation = ", Mean[timelist]]
Print["STD time per calculation = ", StandardDeviation[timelist]]
Just some notes on things
ngrid,delr, delk, rvalues, kvalues are just the values used in making the problem discrete. Typically they are
ngrid = 2048;
delr = 4/100;
delk = \[Pi]/delr/ngrid;
rvalues = Table[(i - 1/2) delr, {i, 1, ngrid}];
kvalues = Table[(i - 1/2) delk, {i, 1, ngrid}];
All matrices being used are 2 x 2 with identical off-diagonals
The identity matrix and the P matrix(it is actually for the density) are
p = {{na pa, 0}, {0, nb pb}};
id = {{1, 0}, {0, 1}};
The major slow spots in the calculation I have identified are the FourierDST calculations (the forward and back transforms account for close to 40% of the calculation time) The gammahat calculation accounts for 40% of the time with the remaining time dominated by the AFD calculation.)
On my i7 Processor the average calculation time per cycle is 1.52 seconds. My hope is to get it under a second but that may not be possible.
My hope had been to introduce some parallel computation this was tried with both ParallelTable commands as well as using the ParallelSubmit WaitAll. However, I found that any speedup from the parallel calculation was offset by the communication time from the Master Kernel to the the other Kernels.(at least that is my assumption as calculations on new data takes twice as long as just recalculating the existing data. I assumed this meant that the slowdown was in disseminating the new lists) I played around with DistributDefinitions as well as SetSharedVariable, however, was unable to get that to do anything.
One thing I am wondering is if using Table for doing my discrete calculations is the best way to do this?
I had also thought I could possibly rewrite this in such a manner as to be able to compile it but my understanding is that only will work if you are dealing with machine precision where I am needing to working with higher precision to get convergence.
Thank you in advance for any suggestions.
I will wait for the code acl suggests, but off the top, I suspect that this construct:
Table[Extract[gammafirst, {i, 1, 1}], {i, hcloselenAA}]
may be written, and will execute faster, as:
gammafirst[[hcloselenAA, 1, 1]]
But I am forced to guess the shape of your data.
In the several lines using:
FourierDST[SetPrecision[Table[gammahat[[i, 1, 1]], {i, ngrid}], 32], 4];
you could remove the Table:
FourierDST[SetPrecision[gammahat[[All, 1, 1]], 32], 4];
And, if you really, really need this SetPrecision, couldn't you do it at once in the calculation of gammahat?
AFAI can see, all numbers used in the calculations of gammahat are exact. This may be on purpose but it is slow. You might consider using approximate numbers instead.
EDIT
With the complete code in your latest edit just adding an //N to your 2nd and 3rd line cuts timing at least in half without reducing numerical accuracy much. If I compare all the numbers in res={gammafirst, gammasecond, AFD} the difference between the original and with //N added is res1 - res2 // Flatten // Total ==> 1.88267*10^-13
Removing all the SetPrecision stuff speeds up the code by a factor of 7 and the results seem to be of similar accuracy.