I am trying to figure out, if this really is the fastest approach. I want this to be as fast as possible, cache friendly, and serve a good time complexity.
DEMO: https://dotnetfiddle.net/BUGz8s
private static void InvokeMe()
{
int hz = horizontal.GetLength(0) * horizontal.GetLength(1);
int vr = vertical.GetLength(0) * vertical.GetLength(1);
int hzcol = horizontal.GetLength(1);
int vrcol = vertical.GetLength(1);
//Determine true from Horizontal information:
for (int i = 0; i < hz; i++)
{
if(horizontal[i / hzcol, i % hzcol] == true)
System.Console.WriteLine("True, on position: {0},{1}", i / hzcol, i % hzcol);
}
//Determine true position from vertical information:
for (int i = 0; i < vr; i++)
{
if(vertical[i / vrcol, i % vrcol] == true)
System.Console.WriteLine("True, on position: {0},{1}", i / vrcol, i % vrcol);
}
}
Pages I read:
Is there a "faster" way to iterate through a two-dimensional array than using nested for loops?
Fastest way to loop through a 2d array?
Time Complexity of a nested for loop that parses a matrix
Determining the big-O runtimes of these different loops?
EDIT: The code example, is now, more towards what I am dealing with. It's about determining a true point x,y from a N*N Grid. The information available at disposal is: horizontal and vertical 2D arrays.
To NOT cause confusion. Imagine, that overtime, some positions in vertical or horizontal get set to True. This works currently perfectly well. All I am in for, is, the current approach of using one for-loop per 2D array like this, instead of using two for loops per 2D array.
Time complexity for approach with one loop and nested loops is the same - O(row * col) (which is O(n^2) for row == col as in your example for both cases) so the difference in the execution time will come from the constants for operations (since the direction of traversing should be the same). You can use BenchmarkDotNet to measure those. Next benchmark:
[SimpleJob]
public class Loops
{
int[, ] matrix = new int[10, 10];
[Benchmark]
public void NestedLoops()
{
int row = matrix.GetLength(0);
int col = matrix.GetLength(1);
for (int i = 0; i < row ; i++)
for (int j = 0; j < col ; j++)
{
matrix[i, j] = i * row + j + 1;
}
}
[Benchmark]
public void SingleLoop()
{
int row = matrix.GetLength(0);
int col = matrix.GetLength(1);
var l = row * col;
for (int i = 0; i < l; i++)
{
matrix[i / col, i % col] = i + 1;
}
}
}
Gives on my machine:
Method
Mean
Error
StdDev
Median
NestedLoops
144.5 ns
2.94 ns
4.58 ns
144.7 ns
SingleLoop
578.2 ns
11.37 ns
25.42 ns
568.6 ns
Making single loop actually slower.
If you will change loop body to some "dummy" operation - for example incrementing some outer variable or updating fixed (for example first) element of the martix you will see that performance of both loops is roughly the same.
Did you consider
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
Console.Write(string.Format("{0:00} ", matrix[i, j]));
Console.Write(Environment.NewLine + Environment.NewLine);
}
}
It is basically the same loop as yours, but without / and % that compiler may or may not optimize.
Related
I have a Dictionary<int, List<int>>, where the Key represents an element of a set (or a vertex in an oriented graph) and the List is a set of other elements which are in relation with the Key (so there are oriented edges from Key to Values). The dictionary is optimized for creating a Hasse diagram, so the Values are always smaller than the Key.
I have also a simple sequential algorithm, that removes all transitive edges (e.g. I have relations 1->2, 2->3 and 1->3. I can remove the edge 1->3, because I have a path between 1 and 3 via 2).
for(int i = 1; i < dictionary.Count; i++)
{
for(int j = 0; j < i; j++)
{
if(dictionary[i].Contains(j))
dictionary[i].RemoveAll(r => dictionary[j].Contains(r));
}
}
Would it be possible to parallelize the algorithm? I could do Parallel.For for the inner loop. However, this is not recommended (https://msdn.microsoft.com/en-us/library/dd997392(v=vs.110).aspx#Anchor_2) and the resulting speed would not increase significantly (+ there might be problems with locking). Could I parallelize the outer loop?
There is simple way to solve the parallelization problem, separate data. Read from original data structure and write to new. That way You can run it in parallel without even need to lock.
But probably the parallelization is not even necessary, the data structures are not efficient. You use dictionary where array would be sufficient (as I understand the code You have vertices 0..result.Count-1). And List<int> for lookups. List.Contains is very inefficient. HashSet would be better. Or, for more dense graphs, BitArray. So instead of Dictionary<int, List<int>> You can use BitArray[].
I rewrote the algorithm and made some optimizations. It does not make plain copy of the graph and delete edges, it just construct the new graph from only the right edges. It uses BitArray[] for input graph and List<int>[] for final graph, as the latter one is far more sparse.
int sizeOfGraph = 1000;
//create vertices of a graph
BitArray[] inputGraph = new BitArray[sizeOfGraph];
for (int i = 0; i < inputGraph.Length; ++i)
{
inputGraph[i] = new BitArray(i);
}
//fill random edges
Random rand = new Random(10);
for (int i = 1; i < inputGraph.Length; ++i)
{
BitArray vertex_i = inputGraph[i];
for(int j = 0; j < vertex_i.Count; ++j)
{
if(rand.Next(0, 100) < 50) //50% fill ratio
{
vertex_i[j] = true;
}
}
}
//create transitive closure
for (int i = 0; i < sizeOfGraph; ++i)
{
BitArray vertex_i = inputGraph[i];
for (int j = 0; j < i; ++j)
{
if (vertex_i[j]) { continue; }
for (int r = j + 1; r < i; ++r)
{
if (vertex_i[r] && inputGraph[r][j])
{
vertex_i[j] = true;
break;
}
}
}
}
//create transitive reduction
List<int>[] reducedGraph = new List<int>[sizeOfGraph];
Parallel.ForEach(inputGraph, (vertex_i, state, ii) =>
{
{
int i = (int)ii;
List<int> reducedVertex = reducedGraph[i] = new List<int>();
for (int j = i - 1; j >= 0; --j)
{
if (vertex_i[j])
{
bool ok = true;
for (int x = 0; x < reducedVertex.Count; ++x)
{
if (inputGraph[reducedVertex[x]][j])
{
ok = false;
break;
}
}
if (ok)
{
reducedVertex.Add(j);
}
}
}
}
});
MessageBox.Show("Finished, reduced graph has "
+ reducedGraph.Sum(s => s.Count()) + " edges.");
EDIT
I wrote this:
The code has some problems. With the direction i goes now, You can delete edges You would need and the result would be incorrect. This turned out to be a mistake. I was thinking this way, lets have a graph
1->0
2->1, 2->0
3->2, 3->1, 3->0
Vertex 2 gets reduced by vertex 1, so we have
1->0
2->1
3->2, 3->1, 3->0
Now vertex 3 gets reduced by vertex 2
1->0
2->1
3->2, 3->0
And we have a problem, as we can not reduce 3->0 which stayed here because of reduced 2->0. But it is my mistake, this would never happen. The inner cycle goes strictly from lower to higher, so instead
Vertex 3 gets reduced by vertex 1
1->0
2->1
3->2, 3->1
and now by vertex 2
1->0
2->1
3->2
And the result is correct. I apologize for the error.
I'm new here and sorry If my question is stupid, but I really need you help.
I need to sort that two dimensional string array by id (the first column):
string [,] a = new string [,]
{
{"2","Pena","pena"},
{"1","Kon","kon"},
{"5","Sopol","sopol"},
{"4","Pastet","pastet"},
{"7","Kuche","kuche"}
};
The problem is that I'm sorting only the number and I want after them to sort the words. That's what I did so far
static void Main(string[] args)
{
string [,] a = new string [,]
{
{"2","Pena","pena"},
{"1","Kon","kon"},
{"5","Sopol","sopol"},
{"4","Pastet","pastet"},
{"7","Kuche","kuche"}
};
int b = a.GetLength(0);
Console.WriteLine(b);
Console.WriteLine(a[0,0]);
Console.WriteLine(a[0,1]);
Console.WriteLine(a[1,0]);
InsertionSort(a, b);
Console.WriteLine();
Console.Write("Sorted Array: ");
printArray(a);
Console.WriteLine();
Console.Write("Press any key to close");
Console.ReadKey();
}
public static void InsertionSort(string[,] iNumbers, int iArraySize)
{
int i, j, index;
for (i = 1; i < iArraySize; i++)
{
for (int k = 0; k < iNumbers.GetLength(1); k++)
{
index = Convert.ToInt32(iNumbers[i, 0]);
j = i;
while ((j > 0) && (Convert.ToInt32(iNumbers[j - 1, 0]) > index))
{
iNumbers[j, k] = iNumbers[j - 1, k];
j = j - 1;
}
iNumbers[j, 0] = Convert.ToString(index);
}
}
}
static void printArray(string[,] iNumbers)
{
for (int i = 0; i < iNumbers.GetLength(0); i++)
{
for (int k = 0; k < iNumbers.GetLength(1); k++)
{
Console.Write(iNumbers[i, k] + " ");
}
}
Console.WriteLine();
}
Unfortunatelly as output I get
1 Pena pena 2 Kon kon 4 Sopol sopol 5 Pastet pastet 7 Kuche kuche
I would be really grateful if you could help me.
Based on the nature of the example and the question, I am guessing that this is a homework assignment and so must be implemented in a fashion that is a) not far from your current example, and b) actually demonstrates an insertion sort.
With that in mind, the following is a corrected version of your example that works:
public static void InsertionSort(string[,] iNumbers, int iArraySize)
{
int i, j, index;
for (i = 1; i < iArraySize; i++)
{
index = Convert.ToInt32(iNumbers[i, 0]);
j = i;
while ((j > 0) && (Convert.ToInt32(iNumbers[j - 1, 0]) > index))
{
for (int k = 0; k < iNumbers.GetLength(1); k++)
{
string temp = iNumbers[j, k];
iNumbers[j, k] = iNumbers[j - 1, k];
iNumbers[j - 1, k] = temp;
}
j = j - 1;
}
}
}
I made two key changes to your original code:
I rearranged the k and j loops so that the k loop is the inner-most loop, rather than the j loop. Your j loop is the one performing the actual sort, while the k loop is what should be actually moving a row for an insertion operation.
In your original example, you had this reversed, with the result that by the time you went to sort anything except the index element of a row, everything looked sorted to the code (because it's only comparing the index element) and so nothing else got moved.
With the above example, the insertion point is determined first, and then the k loop is used simply to do the actual insertion.
I added logic to actually swap the elements. In your original code, there wasn't really a swap there. You had hard-coded the second part of a swap, simply copying the index element to the target, so the swap did work for the index element. But it wouldn't have achieved the swap for any other element; instead, you'd just have overwritten data.
With the above, a proper, traditional swap is used: one of the values to be swapped is copied to a temp local variable, the other value to be swapped is copied to the location of the first value, and then finally the saved value is copied to the location of the second.
The above should be good enough to get you back on track with your assignment. However, I will mention that you can get rid of the k loop altogether if your teacher will allow you to implement this using jagged arrays (i.e. a single-dimensional array containing several other single-dimensional arrays), or by using a second "index array" (i.e. where you swap the indexes relative to the original array, but leave the original array untouched).
I have this for loop. TicketList starts with 109 tickets. nColumns = 100. I calculate the number of rows I will need depending on the number of tickets. So in this case I need 2 rows. Row one will be full and row two will only have 9 entries. I have the loop below. It only runs one time for the NumOfRows and fills the first 100 and never loops.
What am I missing?
for (int j = 0; j < NumOfRows; j++)
{
for (int i = 0; i < nColumns; i++)
{
if (TicketList.Count() > 0)
{
t = rand.Next(0, TicketList.Count() - 1);
numbers[i, j] = TicketList[t];
TicketList.Remove(TicketList[t]);
}
}
}
Try changing your code to use a more LINQ-like, functional approach. If might make the logic easier. Something like this:
TicketList
.OrderBy(x => rand.Next())
.Select((ticket, n) => new
{
ticket,
j = n / NumOfRows,
i = n % NumOfRows
})
.ToList()
.ForEach(x =>
{
numbers[x.i, x.j] = x.ticket;
});
You may need to flip around x.i & x.j or use nColumns instead of NumOfRows - I wasn't sure what your logic was looking for - but this code might work better.
Other than a few poor choices, your loops appear to be fine. I would venture that NumOfRows is not being calculated correctly.
The expression NumOfRows = (TotalTickets + (Columns - 1)) / Columns; should calculate the correct number of rows.
Also, you should use the property version of Count rather than the Linq extension method and use IList<T>.RemoveAt() or List<T>.RemoveAt rather than Remove(TicketList[T]).
Using Remove() requires that the list be enumerated to locate the element to remove, which may not be the same index that you are targeting. Not to mention that you will scan 50% (on average) of the list for each Remove call, when you already know the correct index to remove.
The functional approach listed earlier seems like overkill.
I've attempted to replicate your issue, assuming certain facts about the various variables in use. The loop repeats the expected number of times.
static void TestMe ()
{
List<object> TicketList = new List<object>();
for (int index = 0; index < 109; index++)
TicketList.Add(new object());
var rand = new Random();
int nColumns = 100;
int NumOfRows = (TicketList.Count + (nColumns - 1)) / nColumns;
object[,] numbers;
int t;
numbers = new object[nColumns, NumOfRows];
for (int j = 0; j < NumOfRows; j++)
{
Console.WriteLine("OuterLoop");
for (int i = 0; i < nColumns; i++)
{
if (TicketList.Count > 0)
{
t = rand.Next(0, TicketList.Count - 1);
numbers[i, j] = TicketList[t];
TicketList.RemoveAt(t);
}
}
}
}
The problem that you are seeing must be the result of something that you have not included in your sample.
I am doing an image processing assignment where I want to implement erosion and dilation algorithm. It needs to look for each pixel in all directions (in this case up, down, left and right), so i'm using a plus structuring element. Here is my problem: I've got 4 for loops nested, which makes this operation very slow.
Can anyone tell me how to make the erosion process quicker without using unsafe method?
Here is what I have:
colorlistErosion = new List<Color>();
int colorValueR, colorValueG, colorValueB;
int tel = 0;
for (int y = 0; y < bitmap.Height; y++)
{
for (int x = 0; x < bitmap.Width; x++)
{
Color col = bitmap.GetPixel(x, y);
colorValueR = col.R; colorValueG = col.G; colorValueB = col.B;
//Erosion
for (int a = -1; a < 2; a++)
{
for (int b = -1; b < 2; b++)
{
try
{
Color col2 = bitmap.GetPixel(x + a, y + b);
colorValueR = Math.Min(colorValueR, col2.R);
colorValueG = Math.Min(colorValueG, col2.G);
colorValueB = Math.Min(colorValueB, col2.B);
}
catch
{
}
}
}
colorlistErosion.Add(Color.FromArgb(0 + colorValueR, 0+colorValueG, 0+colorValueB));
}
}
for (int een = 0; een < bitmap.Height; een++)
for (int twee = 0; twee < bitmap.Width; twee++)
{
bitmap.SetPixel(twee, een, colorlistErosion[tel]);
tel++;
}
how to make the erosion process quicker without using unsafe method?
You can turn the inner loops into Parallel.For().
But I'm not 100% sure if GetPixel() and especially SetPixel() are thread-safe. That is a deal-breaker.
Your algorithm is inherently slow due to the 4 nested loops. You're also processing the bitmap using the slowest approach possible bitmap.GetPixel.
Take a look at SharpGL. If they don't have your filters you can download the source code and figure out how to make your own.
I have matrix with 3 dimension (n*m*k). I am trying to fined the maximum number for each n and m by searching in k dimension.((I try to find the maximum number in k dimension for each n and m)) and at last i have a 2d matrix (n*m). i have the following code but it is so slow. Is there any new code or any changes to the current code that do this more quickly.
thanks.
my c# code: note: li is the 3 dimension matrix and they are grater or equal to zero.
int[,] array2 = new int[n, m];
int[,] array = new int[n, m];
List<Array> li = new List<Array>();
for(int k = 0; k <'not a specific value, change each time' ; k++)
{
li.Add(array);
%% changing array
} %% so li will became a (n*m*k) matrix
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
{
int ma = -2;
int d = 0;
while (d <= k)
{
ma = Math.Max(ma, Convert.ToInt32(li[d].GetValue(i, j)));
d++;
}
array2[i, j] = ma;
}
The biggest performance issue is that you use Array objects as elements of your list. This makes it so that every element access using GetValue boxes the value, i.e. allocates a new tiny object to hold the element value.
Your code will run a lot faster if you replace
List<Array> li = new List<Array>();
with
List<int[,]> li = new List<int[,]>();
and
ma = Math.Max(ma, Convert.ToInt32(li[d].GetValue(i, j)));
with
ma = Math.Max(ma, li[d][i, j];
Since you don't know the 3rd dimension in advance, it is harder to use 3D arrays.
An entirely different approach would be to compute the maximum as you're building the list li. This will help in two ways: 1. You avoid indexing into the list of arrays and 2. as long as m and n aren't too large, you improve locality. That is: the values you're working with are closer together in memory, and more likely to be in the processor cache.
This should do the trick (even though it could be kinda slower than your approach):
// put this at the top of your source file
using System.Linq;
// put this where you calculate the maxima
for(int i = 0; i < array2.GetLength(0); ++i)
for(int j = 0; j < array2.GetLength(1); ++j)
{
array2[i, j] = Convert.ToInt32(li.Max(x => x.GetValue(i, j)));
}
You could use a three-dimensional array like this:
int xRange = 10;
int yRange = 10;
int zRange = 10;
int[, ,] matrix = new int[xRange, yRange, zRange];
// set up some dummy values
for (int x = 0; x < xRange; x++)
for (int y = 0; y < yRange; y++)
for (int z = 0; z < zRange; z++)
matrix[x, y, z] = x * y * z;
// calculate maximum values
int[,] maxValues = new int[xRange, yRange];
/* LINQ version of maximum calculation
for (int x = 0; x < xRange; x++)
for (int y = 0; y < yRange; y++)
maxValues[x, y] = Enumerable.Range(0, zRange).Select(z => matrix[x, y, z]).Max();
*/
// longhand version of maximum calculation
for (int x = 0; x < xRange; x++)
for (int y = 0; y < yRange; y++)
for (int z = 0; z < zRange; z++)
maxValues[x, y] = Math.Max(maxValues[x, y], matrix[x, y, z]);
// display results
for (int x = 0; x < xRange; x++)
{
for (int y = 0; y < yRange; y++)
Console.Write("{0}\t", maxValues[x, y]);
Console.WriteLine();
}
From an algorithm perspective, there's no more efficient way to evaluate the maximum value for fixed n,m for all k. It will take O(n*m*k) operations.
Now, the only way to improve performance is to find improvements in your implementation, particularly in your storage of the 3D matrix.
Using List<Array> is a major area for improvement. You are prone to boxing issues (conversion of primitive types to objects) and making more function calls than are necessary.
Reduce your 3D matrix to an array of primitives:
int[] my3DArray = new int[n * m * l]; // Note I'm using l where you use k
Now index into your array at [i, j, k] using the following offset:
int elementAtIJK = my3DArray[i + (n * j) + (m * n * k)];
If you just use arrays of primitives you should see a definite improvement.
Edit:
In fact, in C# (and several other languages) it's very easy to implement 3D arrays directly, e.g.:
int[,,] my3DArray = new int[n,m,l];
int elementAtIJK = my3DArray[i,j,k];
Which is much simpler than I first described (but at the end of the day is internally translated in the 1D form).
What to do if the 3rd dimension varies in size...
Now, it gets more interesting if the size of the 3rd dimension varies significantly. If it has a known maximum and isn't too big, you can simply set it to the maximum and fill the empty values with zeroes. This is simple and may meet your needs.
However, if the 3rd dimension can be very big, all these extra stored zeroes could waste a lot of valuable space and what you need is a Sparse Matrix representation.
There are different storage mechanisms for sparse matrices. For your purposes, you could consider your 3D array to be a 2D matrix, with (n*m) rows and max(k) columns. As the 3rd dimension varies in length, there are lots of empty spaces in your columns. This is called a sparse row and the standard data storage for this is "Compressed Sparse Row". Again, for performance this can be represented just by three primitive arrays, a data array, a row index array and a column pointer array. There are resources elsewhere on the web that describe the CSR implementation better than I can, but hopefully this will point you in the right direction.