TLDR: I need to average the values of all the surrounding coordinates for a specific coordinate for every coordinate in a 3D array
I am making a simplistic weather simulating program in Godot C# and have run into a few problems along the way.
One of the biggest problems I have encountered is performance, along with a few other things. To simulate air flow, I have a 3D array containing direction (Vector3 objects) for each coordinate. To simulate the airflow, I set each voxel’s direction to the average of the directions of the surrounding voxels.
Each voxel has a pressure value, and a voxel transfers pressure scaled by the magnitude (speed) of the wind direction to the voxels the wind direction is pointing to. For example if a voxel at (x,y,x) has a direction of (1,1,1), the voxel at (x+1,y+1,z+1) will have its pressure set to (x+1,y+1,z+1).pressure + direction.project(Vector3(x+1,y+1,z+1)).length() * (x,y,z).pressure
A voxel will also add Vector3’s pointing towards neighboring voxels if the pressure difference is not 0. The length of these vectors will be scaled by the pressure difference.
There are a bunch of other properties that need to be averaged up such as temperature, humidity, density, etc.
The real issue is iterating through a 3D array in a way that is fast, very fast. The method I am using at the moment has six nested for loops: Three for iterating over each voxel in the array, and three for iterating over the neighboring voxels within a range of -1 to 1 in each direction. I want to simulate a 16x16x16 area, but this algorithm requires me to do 16x16x16x27 iterations every game tick, rendering the application unplayable.
Is there a more efficient way of doing this?
First, make sure your nested loops are accessing memory in order of the memory's physical location. A 3D array is just a 1D array with some extra strides and offsets that occur behind the scenes. If your array is organized as voxels[x, y, z], then your final nested loop should be the z loop. If you prefer to access voxels in a different pattern, then you can populate your array differently to accommodate the other pattern, such as voxels[z, y, x].
Second, try to eliminate repeat access of array locations on different loops. If you access a location on one loop and you plan to access it again on the next, try saving the info to a local variable and test to see if it improves speed.
Third, see if you can reduce the number of calculations. For example, if you are calculating an average of all variables in a 3x3x3 grid and then incrementing the location and repeating, you can try saving a running sum. Then on the next loop subtract the 3x3 section you no longer need, add the new 3x3 section, and then divide to get your new average.
On a side note, maybe your example is truncated or conceptual, but it doesn't look like you are actually averaging the values of all surrounding voxels. Each voxel will be surrounded by a 3x3x3 array of voxels (so 26 adjacent voxels when excluding the center voxel). If we exclude corners, there are still 6 adjacent voxels.
So I have a simulation I run that has 3 lists of about 200k objects. Each object holds information about a point(x,y,z) and contains an array of x objects.
Depending on the amount of frames (of the animation) in the simulation, each Point object holds an array of say 64 values.
The whole simulation takes up about 11 gigabytes of RAM. This is too much for a lot of our users. Therefore i would like to know if there are smart ways to save memory usage in this case.
At least 60% of the arrays within these points hold the value 0. I have thought of ways to use lists as pointers so that the same value (for example 0) doesn't get saved in memory a few million times, like I would in C++. However I cannot come up with an implementation for this in C#.
Any tips or tricks to reduce the 11 gigabytes of RAM the simulation occupies are well appreciated!
The Point object as described above is:
public class Vertex {
public Point3D position;
public float[] delta;
}
There is also 3 meshes. Those hold the objects in:
public List<Vertex> Vertices;
The way the arrays are filled is with another list of points, roughly aligned with the mesh, but not exactly with each vertex, the position of these points change every frame, so each frame, each point has to assign a fraction of its value to each of the nearby vertices. So filling the vertices is not as straight forward as it looks.
I currently approached this by initializing the array with a size of e.g. 64. And then depending on whether there are any close points, a value (or an average of multiple) is assigned to the position of the current frame in that array.
Using the approach of #kookiz might be possible but will be harder than it looks on the surface.
For example: A two-dimensional array can be visualized like a brick-wall with square bricks, where every brick represents a coordinate in our array. A 3-dimensional array can in the same way be visualized as a box, or cube.
But, here is the tricky part, how do you visualize an array with multiple (More than 3) dimensions? Or, for that part, how do you visualize an array with not only multiple dimensions, but multiple dimensions in several layers?
For example: How do you visualize an array such as this: Array[3,3,3,3][3,3][3,3,3,3,3][3]?
How you visualize the arrays really depends on their practical use. If you are using the arrays for spacial relations then you can benefit from imagining it as a cube, but you also lose the need to imagine more than 3 dimensions. If you really and truly wanted to implement a fourth time dimension, you could just imagine your cube with the contents changing as time progresses.
Otherwise you may be keeping track of strongly related records. Perhaps each of the first elements is a galaxy, the second-level elements are star clusters, the third-level elements are solar systems, the fourth-level elements are planets, the fifth-level elements are continents...
In this case you can imagine it was arrays within arrays. If you need a 4-dimensional array then you can imagine a cube, but each sub-cube is actually a one-dimensional array.
If you need a 5-dimensional array then you can imagine a cube, but each sub-cube is divided into your "brick wall" example.
6-dimensional is a cube with each sub-cube being its own divided cube.
This tends to fall apart at after 6 dimensions. Beyond this there is usually a more practical reason that you need so many dimensions. For example, websites like eHarmony do their match-making by using normal geometry on 20+ -dimensional spaces. You have one dimension for "humor", one for "good looks", one for "love of shopping"... Then you can take two people and apply distance formula (square each of the dimensional differences, add these differences, square root) and determine how compatible the two people are. So if one person scored "5, 3, 9, 2, 8, 4, 7, 3, 1" on our 9-dimensional personality matrix and another scored "9, 3, 7, 1, 8, 2, 8, 4, 7" then your compatibility is:
sqrt((5-9)^2+(3-3)^2+(9-7)^2+...)
This can be applied over infinite dimensions and still work. Since these dimensions don't apply to space, however, there's no need to visualize them as such. Instead, in this particular case, we can actually imagine it as just a single-dimensional array with several integer values. The reason we can simplify this array, mind you, is that our multi-dimensional array only contains a single "1" and all of the rest are "0"s (indicating the location of the person in this array).
Moving away from the eHarmony example, the point is- after a certain amount of dimensions you usually have a practical purpose for the array which lends itself to a method of perceiving it.
Some people can mentally model n-dimensional geometry for n > 3, at least as far as simple shapes go, and some cannot. (I was quite surprised when recently talking to someone whose field was advanced n-dimensional geometry to learn that he couldn't visualise a hypercube, while I can but find his mathematics quite beyond me).
It isn't really necessary though. Indeed, it's rarely particularly necessary to visualise a two-dimensional array as Cartesian coördinates either - when you are using a 2-dimensional array in practice you have some purpose for each axis, and that purpose quickly becomes more important than any visual representation.
If you do need to, then consider that a 2-dimensional array can also be considered as an ordered set of 1-dimensional structures. Likewise a 3-dimensional array can be considered an ordered set of 2-dimensional structures, or a set of sets of 1-dimensional (with these sets of equal size - allowing different sizes moves matters into jagged arrays).
Hence a 4-dimensional array can be considered an ordered set of 3-dimensional structures, and so on.
You don't. It's rare that you even need more than 2 or 3 dimensions. If you need more than that, then perhaps the extra dimensions should be modeled as properties on an object instead, in which case you can see them as attributes and not try to imagine some mythical hypercube.
There are many lovely ways to visualize multidimensional data. One of my favorites is Alfred Inselberg's Parallel Coordinates, which represents each dimension as a vertical axis, and each data point as a thread connecting them all:
Another great visualization is Ramana Rao's Table Lens (pdf):
This represents each dimension as a column, as in a spreadsheet, but graphically rather than numerically. It is particularly good at showing correlation between dimensions; as you sort by one dimension, it is easy to see how correlated dimensions sort alongside it.
Try being subtractive about it. If you need to imagine, say, a ten dimensional array then start by imagining the set of all n-dimensional real-valued Euclidean vector spaces for all finite non-negative integers n. { R0, R1, R2, ... }
Now imagine taking away almost all of that, leaving just R10.
Now imagine taking away almost all of that, so that you have just the integer lattice points in R10 left.
Now imagine taking away almost all of that, so that you have just a hyper-rectangular subset of the integer lattice points.
And you're done; that's a good visualization of a 10-dimensional array. It's really very small when you think about it as a subset of the set of all possible n-dimensional vector spaces.
If the subject of high-dimensional spaces interests you, you might want to read my gentle introduction to some interesting facts about search algorithms on high-dimensional vector space databases:
http://blogs.msdn.com/b/ericlippert/archive/tags/high+dimensional+spaces/
Over 3 dimensions, your only options are either a tree view or a drill-down.
The same way you visualize 4 spatial dimensions: "slice", superimpose, or project it onto what you already understand and can visualize.
Think of every extra dimension as an "enclosing box". Think of a 2D array as an array of 1D arrays, of a 3D array as an array of 2D arrays, and so on.
Here are some examples...
1D 1x2 array:
[ 1, 2 ]
2D 2x2 array:
{ [ 1, 2 ], [ 3, 4 ] }
{ [ 5, 6 ], [ 7, 8 ] }
3D 2x2x2 array:
( { [ 1, 2 ], [ 3, 4 ] }, { [ 5, 6 ], [ 7, 8 ] } )
( { [ 9, 0 ], [ 1, 2 ] }, { [ 3, 4 ], [ 5, 6 ] } )
You could visualise a financial report as an array where data is coming in from multiple entities in spreadsheet form:
a single spreadsheet of sales data would be a 2D array (e.g. sales for each month in the quarter per profit centre);
multiple tabs in a workbook (one for each subsidiary) would be a 3D array;
Then, for purposes of global consolidation, a Controller may receive a workbook from each Region - this would be the 4th dimension. A fifth dimension could be "time" if you have a need to manipulate sales data over time (to spot trends for instance).
In theory, you could hold multi-year, multi-region sales data in a single 5D array variable.
As people have said above, you really need to have an application in mind first and then the logical data structure will help define a suitable physical form. Any set of attributes that can be modelled relationally can be placed in an array normally.
tony
Visualize a 4D array as a 1D array of cubes. A 5D array as a 2D array of cubes. And a 6D array as a 3D array of cubes, or a cube of cubes. A 7D array as a 1D array of cubes of cubes, etc...
Ignoring whether these dimensions are neeeded, why not just envision a 4D array as a 1D array (line) of "cubes". (ie: an 1D array where each element points to a 3D cube). This can be scaled up as needed (ie: 2D surface where each element points to a cube). This of course isn't how a hypercube would 'look', but that isn't required.
tabs :)
tabs of 3 dimensional data gives you 4 dimensions, tabs of tabs gives you n dimensional.
not thats necessarily the best way to visualize it. Also not good for rotating in any of the dimensions.
but then, it depends what you are trying to visualise
RGB for instance can be turned into a 2D map and then projected onto a cube, giving you 4d information
Not looking to give away the farm here, but this is an example of how I look at multidimensional arrays in PHP.
$map[room][x][y][z][id][photopath][flag1][flag2]
I imagine what it would look like as a point in 3D space, then I just add sorting attributes. Here, imagine you're playing Doom 3. Each map is divisible into rooms, which have pixels with x, y, and z coordinates. Each of those points can have an object id (monster, item, etc.) associated with it. I've added more attributes for my application, but this is basically it. A point in the array doesn't necessarily have to be geometrically accurate; it can have any meaning. Whether this is similar to what other people do, I don't know. I do know that using the gd graphics library would make a nice visualizer for multidimensional arrays on the fly, but I didn't get to that project last time I was working for this client.