Looping over 3D array in parallel.for - c#

I have a 3D array with arbitrary X, Y and Z lengths
I want to iterate over it in a parallel.for loop, which can't be nested without wasting tasks afaik
Instead, the single loop's length is ArrayLengthX * ArrayLengthY * ArrayLengthZ
Can I mathematically get the current 3D array element from the current iteration + the X, Y and Z length of the array? if so how?
edit : Example below, hope this is enough to understand what's going on
DimensionSettings dimensionSettings = dimension.Settings;
Vector3Int DimSize = dimensionSettings.GetDimensionSize();
TaskProgressMutex.WaitOne();
CurrentProgress = 0;
TotalProgress = DimSize.x * DimSize.y * DimSize.z;
TaskProgressMutex.ReleaseMutex();
int ChunkAmount = DimSize.x * DimSize.y * DimSize.z;
GD.Print("Chunks to generate : " + ChunkAmount);
ParallelLoopResult result = Parallel.For(0, ChunkAmount, (int i) =>
{
GD.Print(i);
int xcoords = ???;
int ycoords = ???;
int zcoords = ???;
Vector3Int ChunkCoords = new Vector3Int(xcoords, ycoords, zcoords);
GD.Print("Current Chunk : " + xcoords + " " + ycoords + " " + zcoords);
GenerateChunk(ChunkCoords, seed);
TaskProgressMutex.WaitOne();
CurrentProgress += 1;
//GD.Print("Chunk " + xcoords + " " + ycoords + " " + zcoords + " finished generating. Current Progress : " + CurrentProgress);
TaskProgressMutex.ReleaseMutex();
});

My suggestion is to parallelize only the outer loop (the X dimension), and do normal (non-parallel) inner loops for the Y and Z dimensions:
ParallelOptions options = new()
{
MaxDegreeOfParallelism = Environment.ProcessorCount
};
Parallel.For(0, dimSize.X, options, (int x) =>
{
for (int y = 0; y < dimSize.Y; y++)
{
for (int z = 0; z < dimSize.Z; z++)
{
Vector3Int chunkCoords = new (x, y, z);
GenerateChunk(chunkCoords, seed);
}
}
});
The idea is to increase the chunkiness of the parallel work. In general the more chunky is the workload, the less is the overall overhead of the parallelization. At the other extreme, if each unit of work is too chunky, the partitioning of the work may become imbalanced.
Also when you use the Parallel.For/Parallel.ForEach/Parallel.Invoke methods I am suggesting to specify always the MaxDegreeOfParallelism, although this suggestion deviates from the general advice offered in the official documentation.

Related

Want to evaluate the polynomial equation

In this case,this is the array which serves as coefficients and degrees which first value having no degree.
double[] arr = { 12, 2, 3 ,4};
I then made a method to print the above array in terms of polynomial equation.
It gives output in type string as follows :
2x^2 + 3x^3 + 4x^4 + 12
I want to a function which takes an argument x and then solve the above polynomial with respect to value of x.
How can I do that?
Any kind of help will be appreciated!.
Edit: Question Solved
To evaluate it you can simply sum the power values times the coefficients. Using LINQ, that's one line:
double result = arr.Select((c,i) => c * Math.Pow(x, i)).Sum();
Here i is the index into your array, it starts at zero, so x^0 = 1 * 12 == 12 etc.
You can also do it without LINQ like this:
List<string> debug = new List<string>();
double y = 1.0;
result = 0.0;
for (int i = 0; i < arr.Length; i++)
{
debug.Add($"{arr[i]} * x^{i}");
result = result + arr[i] * y;
y = y * x;
}
Console.WriteLine(string.Join(" + ", debug));
Console.WriteLine(result);
Which, for x=3 outputs:
12 * x^0 + 2 * x^1 + 3 * x^2 + 4 * x^3
153
Same result as LINQ.
This is what I created:
for (int i = 1; i < degree.Length; i++)
{
result_first += degree[i] * Math.Pow(x, degree[i]);
}
result_first += degree[0];
It works perfectly.

Calculating Estimated Time Left in Loop (When iteration number is very big and time required for each iteration is very low)

I'm trying to calculate total time remaining of a for loop. Total number of iterations can be more than ~1010000000. Total time required for doing "Real job done here" is much lower than a second and it doesnt change much. When i use my current solution time remaining increases for a long time and than starts to decrease.
I'm looking for a better solution. What can i do?
long totalTiles = ((((rightBottom.X) - (topLeft.X)) + 1) * (((rightBottom.Y) - (topLeft.Y)) + 1));
long currentTileProccessed = 0;
DateTime startTime = DateTime.Now;
for (long x = (topLeft.X); x <= (rightBottom.X); x++)
{
for (long y = (topLeft.Y); y <= (rightBottom.Y); y++)
{
**//Real job done here//**
TimeSpan timeRemaining = TimeSpan.FromTicks(DateTime.Now.Subtract(startTime).Ticks * (totalTiles - (currentTileProccessed + 1)) / (currentTileProccessed + 1));
this.Dispatcher.Invoke((Action)delegate () {
EstimatedTimeLeft_TextBlock.Text = "Days : " + timeRemaining.Days.ToString("D2") + ", Hours : " + timeRemaining.Hours.ToString("D2") + ", Minutes :" + timeRemaining.Minutes.ToString("D2") + ", Seconds :" + timeRemaining.Seconds.ToString("D2");
});
currentTileProccessed++;
}
}
Here I am using Stopwatch from System.Diagnostics to determine the average time for the last 100 tasks, which I multiply against the total expected number of tasks minus the number already run.
NOTE: Remaining time can still increase, if suddenly the last 100 tasks start running slower than the previous 10k, this will readjust your remaining time to match the recent runs.
long totalTiles = ((((rightBottom.X) - (topLeft.X)) + 1) * (((rightBottom.Y) - (topLeft.Y)) + 1));
long currentTileProccessed = 0;
Queue<long> taskTimes = new Queue<long>();
int taskTimeHistoryLimit = 100;
long taskTotal = (rightBottom.X - topLeft.X) * (rightBottom.Y - topLeft.Y);
Stopwatch watch = new Stopwatch();
long index = 0;
for (long x = (topLeft.X); x <= (rightBottom.X); x++)
{
for (long y = (topLeft.Y); y <= (rightBottom.Y); y++)
{
index++;
watch.Start();
//Real job done here//
watch.Stop();
taskTimes.Enqueue(watch.ElapsedTicks);
watch.Reset();
while (taskTimes.Count > taskTimeHistoryLimit)
{
taskTimes.Dequeue();
}
TimeSpan timeRemaining = new TimeSpan((taskTotal - index) * (long)taskTimes.Average());
this.Dispatcher.Invoke((Action)delegate () {
EstimatedTimeLeft_TextBlock.Text = "Days : " + timeRemaining.Days.ToString("D2") + ", Hours : " + timeRemaining.Hours.ToString("D2") + ", Minutes :" + timeRemaining.Minutes.ToString("D2") + ", Seconds :" + timeRemaining.Seconds.ToString("D2");
});
}
}

Find symmetric points on a parabola C#

I have searched through many posts and cannot find what I need. I see solutions to find the closest number to a target but I need one that finds that number, then can select the closest number on the other side of a "parabola" shaped set of data that is not completely symmetrical. I essentially use:
List<int> list = new List<int> { 2, 5, 7, 10 };
int number = 9;
int closest = list.Aggregate((x,y) => Math.Abs(x-number) < Math.Abs(y-
number) ? x : y);
This is how I find my first target number. Now I need to find a second number that is almost equal in value but on the other side of a parabola (I really need the indexes of these numbers but I can put the pieces together). My methods keeps coming up a single number. Essentially I need to move to an approximately symmetric index across a parabola to select an equivalent number. To put this in context, I am calculating beam width, i.e. the distance between the sides of a parabola at a specific point. Please let me know if this makes sense and if I need to explain more before you down vote me. I have done extensive research and testing. It is difficult for me to provide more code because it is coming from a $500,000 testing system that does not have internet so I can't copy and paste my code. I can go the extra yard if more code is needed though, just trying to avoid compromising an expensive embedded Windows system.
Here is a related post that I need to go a step further from
located here
Edit adding full code:
fileName = textBox10.Text;
SetupControlState(true);
if (comboBox2.SelectedIndex == 0)
{
cent = false;
}
else if (comboBox2.SelectedIndex == 1)
{
cent = true;
}
testHPositions = new List<double>();
testHMeasurements = new List<double>();
testVPositions = new List<double>();
testVMeasurements = new List<double>();
double horzRange = Double.Parse(textBox12.Text);
double vertRange = Double.Parse(textBox11.Text);
double refGain = Double.Parse(textBox14.Text);
double stepSize = Double.Parse(textBox13.Text);
testBorePos = new double[1, 2];
_worker = new BackgroundWorker();
_worker.WorkerSupportsCancellation = true;
testBoreRun.Enabled = false;
button2.Enabled = true;
_worker.RunWorkerAsync();
_worker.DoWork += new DoWorkEventHandler((state, args) =>
{
// try
// {
dev1 = new VisaDevice("inst0", "TCPIP0::192.168.0.10::inst0::INSTR"); //textBox1.Text);
if (!cent)
{
Double startfreq = double.Parse(textBox2.Text) * 1000000000;
Double stopfreq = double.Parse(textBox1.Text) * 1000000000;
dev1.SendBlocking("FREQ:STAR " + startfreq.ToString(), true);
string responseFreq = "";
dev1.QueryBlocking("FREQ:STAR?", ref responseFreq, true);
dev1.SendBlocking("FREQ:STOP " + stopfreq.ToString(), true);
dev1.QueryBlocking("FREQ:STOP?", ref responseFreq, true);
}
else if (cent)
{
Double freq = double.Parse(textBox9.Text) * 1000000000;
Double span = double.Parse(textBox8.Text) * 1000000000;
dev1.SendBlocking("FREQ:CENT " + freq.ToString(), true);
string responseFreq = "";
dev1.QueryBlocking("FREQ:CENT?", ref responseFreq, true);
dev1.SendBlocking("FREQ:SPAN " + span.ToString(), true);
dev1.QueryBlocking("FREQ:SPAN?", ref responseFreq, true);
// this.InvokeEx(f => f.stringReadTextBox.AppendText("Spectrum Analyzer Connected" + Environment.NewLine));
}
string progID;
Util U = new Util();
progID = "ASCOM.iOptron.Telescope";
if (progID != "")
{
PauseClass pause;
pause = new PauseClass();
Telescope T = new Telescope(progID);
T.Connected = true;
pause.Pause(5000);
T.Tracking = false;
T.TargetDeclination = 1;
T.TargetRightAscension = 1;
this.InvokeEx(f => f.stringReadTextBox.AppendText(" Connected to " + progID + Environment.NewLine));
this.InvokeEx(f => f.stringReadTextBox.AppendText(" Connected to Spectrum Analyzer" + Environment.NewLine));
T.SlewToAltAz(180.00, 45 - vertRange);
double Alt = T.Altitude;
for (int i = 0; i < ((vertRange * 2) / stepSize) + 1; i++)
{
if (_worker.CancellationPending)
break;
T.SlewToAltAz(180, Alt + stepSize * i);
this.InvokeEx(f => f.stringReadTextBox.AppendText("Test Altitude = " +(T.Altitude - 45).ToString("F") + Environment.NewLine));
testVPositions.Add(T.Altitude);
dev1.SendBlocking("INIT", true); //Start single measurement
string respOPC = "", responseState = "", responseMarkerY = "";
dev1.QueryBlocking("*OPC?", ref respOPC, true); //Wait for operation complete
dev1.QueryBlocking("STAT:QUES:MEAS?", ref responseState, true); //Check State
dev1.QueryBlocking("CALC:MARK:Y?", ref responseMarkerY, true); // Get the result
this.InvokeEx(f => f.stringReadTextBox.AppendText(responseMarkerY + Environment.NewLine));
testVMeasurements.Add(Double.Parse(responseMarkerY));
if (testVMeasurements.Count > ((vertRange * 2) / stepSize))
{
this.InvokeEx(f => f.stringReadTextBox.AppendText("Vertical Scanning Is Complete!" + Environment.NewLine));
double maxVamp = testVMeasurements.Max();
int index2 = testVMeasurements.IndexOf(testVMeasurements.Max());
double maxVPos = testVPositions[index2];
testBorePos[0, 1] = maxVPos;
this.InvokeEx(f => f.stringReadTextBox.AppendText("Vertical Max Amplitude = " + maxVamp + Environment.NewLine));
this.InvokeEx(f => f.stringReadTextBox.AppendText("Vertical Position of Max Amplitude = " + (maxVPos - 45).ToString("F") + Environment.NewLine));
}
}
if (!_worker.CancellationPending)
{
T.SlewToAltAz(180.00 - horzRange, testBorePos[0, 1]);
}
double Az = T.Azimuth;
for (int i = 0; i < ((horzRange * 2) / stepSize) + 1; i++)
{
if (_worker.CancellationPending)
break;
if (vertRange > 20)
{
this.InvokeEx(f => f.stringReadTextBox.AppendText("Vertical Range Cannot Be Greater than +/- 20 Degreez" + Environment.NewLine));
break;
}
T.SlewToAltAz(Az + stepSize * i,testBorePos[0,1]);
this.InvokeEx(f => f.stringReadTextBox.AppendText("Test Azimuth = " + (T.Azimuth-180).ToString("F") + Environment.NewLine));
testHPositions.Add(T.Azimuth);
dev1.SendBlocking("INIT", true); //Start single measurement
string respOPC = "", responseState = "", responseMarkerY = "", responseMarkerX = "";
// string responseFreq = "";
dev1.QueryBlocking("*OPC?", ref respOPC, true); //Wait for operation complete
dev1.QueryBlocking("STAT:QUES:MEAS?", ref responseState, true); //Check State
dev1.QueryBlocking("CALC:MARK:Y?", ref responseMarkerY, true); // Get the result
dev1.QueryBlocking("CALC:MARK:X?", ref responseMarkerX, true); // Get the result
this.InvokeEx(f => f.stringReadTextBox.AppendText(responseMarkerY + Environment.NewLine));
testHMeasurements.Add(Double.Parse(responseMarkerY));
if (testHMeasurements.Count > ((horzRange * 2) / stepSize))
{
_worker.CancelAsync();
stop = false;
this.InvokeEx(f => f.testBoreRun.Enabled = true);
this.InvokeEx(f => f.button2.Enabled = false);
this.InvokeEx(f => f.stringReadTextBox.AppendText("Horizontal Scanning Is Complete!" + Environment.NewLine));
double maxHamp =testHMeasurements.Max();
int index =testHMeasurements.IndexOf(testHMeasurements.Max());
double maxHPos =testHPositions[index];
testBorePos[0, 0] = maxHPos;
this.InvokeEx(f => f.stringReadTextBox.AppendText("Horizontal Max Amplitude = " + maxHamp + Environment.NewLine));
this.InvokeEx(f => f.stringReadTextBox.AppendText("Horizontal Position of Max Amplitude = " +( maxHPos-180).ToString("F") + Environment.NewLine));
this.InvokeEx(f => f.stringReadTextBox.AppendText("Antenna Under Test Peak Amplitude located at (" + (testBorePos[0, 0] - 180).ToString("F") + " , " + (testBorePos[0, 1] - 45).ToString("F") + ")" + Environment.NewLine));
this.InvokeEx(f => f.SetupControlState(false));
T.SlewToAltAz(testBorePos[0, 0], testBorePos[0, 1]);
dev1.SendBlocking("INIT", true); //Start single measurement
maxAmpTest = new double();
string respOPC2 = "", responseState2 = "", responseMarkerY2 = "";
dev1.QueryBlocking("*OPC?", ref respOPC2, true); //Wait for operation complete
dev1.QueryBlocking("STAT:QUES:MEAS?", ref responseState2, true); //Check State
dev1.QueryBlocking("CALC:MARK:Y?", ref responseMarkerY2, true); // Get the result
maxAmpTest = Double.Parse(responseMarkerY2);
double target = maxAmpTest - 3;
Here is where I am stuck:
// int indexbeam = testHMeasurements.IndexOf(target);
// indexList = testHMeasurements.IndexOf(testHMeasurements.FindAll(s => s.Equals(target)).First());
double closest = testHMeasurements.Aggregate((x, y) => Math.Abs(x - target) < Math.Abs(y - target) ? x : y);
var result = Enumerable.Range(0, testHMeasurements.Count).Where(j => testHMeasurements[j] ==closest).ToList();
// int beamIndex1 = testHMeasurements.IndexOf(testHMeasurements.OrderBy(item => Math.Abs(target - item)).First());
// int beamIndex2 = testHMeasurements.IndexOf(testHMeasurements.OrderBy(item => Math.Abs((beamIndex1 + 1) - item)).First());
double beam1 =( testHPositions[result[0]]) - 180;
double beam2 = (testHPositions[result[1]]) - 180;
beamWidth = Math.Abs(beam1) + Math.Abs(beam2);
this.InvokeEx(f => f.stringReadTextBox.AppendText("Antenna Under Test Amplitude = " + responseMarkerY2 + Environment.NewLine));
this.InvokeEx(f => f.stringReadTextBox.AppendText(" Antenna Under Test Gain = " + (maxAmpTest - refAmp + refGain) + Environment.NewLine));
this.InvokeEx(f => f.stringReadTextBox.AppendText(" Antenna Under Test Beam Width = " +beamWidth.ToString("F") + Environment.NewLine));
testGain = maxAmpTest - refAmp + refGain;
}
}
T.Connected = false;
T.Dispose();
dev1.Dispose();
if (_worker.CancellationPending)
{
Save();
// Cleanup Excel resources
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
});
First, you must find the parabola. Because your data only approximates the parabola, you need a statistical method called Quadratic Regression, or Polynomial Regression to find the parameters a, b and c of the equation
y = ax2 + bx + c
defining the parabola, that best fits the dataset given by the points
(xi, yi)
Use a math library or google for an algorithm.
Once you have the parabola, determine the symmetry axis of it, i.e. find the x-value of where the minimum or maximum (if the parabola is upside down) of the parabola is.
xs = -b / 2a
Now, once you have a given x-value, you can find a point at the opposite side of the parabola by mirroring x at xs
x' = 2xs - x
This is the explanation for a parabola in 2-D. If you have a parabola in 3-D, i.e. a Paraboloid the principle remains the same, but with more complex math. Google for Paraboloid Regression. A parabolic antenna has a curved surface with the cross-sectional shape of a parabola, called a paraboloid in geometrical terms.
Only once you have solved the mathematical problems, you can start programming and finding points in lists.
Turns out this question could actually be solved through programming with no advanced math required. Given a y-value and asked to find two corresponding x values on an asymmetrical/parabola arc you can simply split the arc at the vertex in two pieces then scan each of the two arrays for the matching x-value. It works like a charm - just requires a little critical thinking and a lot less over thinking it (math major stuff :p)

C# for skipping some

I am asking a question today because I look is skipping certain items and I think it is because its running too fast and doing too much, is there a way to fix this without manually putting a thread.sleep of like 10ms after each loop element?
Is this a known issue? any help would be appreciated! The for loop I am talking about is the 3rd one, the one after the two nested set of for's
There is about 104 items in squares after the first 2 foreach's are ran, there could be up to 1000, what is the best way to stop it skipping?
If I don't put a thread.sleep there, only the first occurence works, the rest of the items in the foreach DONT work
If I do 10ms, 3-4 miss
If I do 15ms they all work
List<string> squares = new List<string>();
var minX = 1;
var minY = 1;
var maxX = room.Model.MapSizeX;
var maxY = room.Model.MapSizeY;
for (var currentX = minX; currentX <= maxX; ++currentX)
{
for (var currentY = minY; currentY <= maxY; ++currentY)
{
if (!room.GetGameMap().ItemCanBePlacedHere(currentX, currentY))
{
continue;
}
squares.Add(currentX + "," + currentY);
}
}
foreach (string tileString in squares)
{
var x = Convert.ToInt32(tileString.Split(',')[0]);
var y = Convert.ToInt32(tileString.Split(',')[1]);
session.SendWhisper("Attempting to place an item in X" + x + " and Y" + y);
if (!room.GetGameMap().ItemCanBePlacedHere(x, y))
{
session.SendWhisper("Can't place an item in X" + x + " Y" + y);
continue;
}
var newItem = new Item(new Random().Next(), room.RoomId, 1536, "", x, y, 0, 0, session.GetPlayerData().Id, 0, 0, 0, "", room);
newItem.ExtraData = "1";
newItem.UpdateState();
room.SendMessage(new ObjectAddComposer(newItem, room));
room.GetGameMap().AddToMap(newItem);
// I only put this here because it skips
// This slows it down a little and doesnt
// Make it skip 3-5 of the items
System.Threading.Thread.Sleep(15);
}

should i create complex nested structures with Linq or traditional loops?

so out of the following 3 examples that do the same thing i really lean towards the first but is it really overkill and an abuse of linq to do things that way where you can create it all as an expression
var Rand = new Random();
Hosts = "abcdef".Select(x =>
{
return new HostMachineToUpdate(x + "_Host",
Enumerable.Range(1, Rand.Next(3, 8))
.Select(y => new VirtualMachineToUpdate(x + y.ToString() + "_VM")).
ToList()
);
}
)
.ToList();
//traditional
Hosts = new List<HostMachineToUpdate>();
for (int x = (int)'a'; x < (int)'e'; x++)
{
var Guests = new List<VirtualMachineToUpdate>();
for (int y = 1; y < (new Random().Next(3, 8));y++ )
{
Guests.Add(new VirtualMachineToUpdate((char)x + y.ToString() + "_VM"));
}
Hosts.Add(new HostMachineToUpdate((char) x + "Host",Guests));
}
//very traditional.
Hosts = new List<HostMachineToUpdate>();
int lower = (int)'a';
int upper = (int)'e';
for (int x = lower; x < upper; x++)
{
List<VirtualMachineToUpdate> Guests = new List<VirtualMachineToUpdate>();
int randomItemNum = new Random().Next(3, 8);
for (int y = 1; y < randomItemNum; y++)
{
string vmname = (char)x + y.ToString() + "_VM";
VirtualMachineToUpdate vm = new VirtualMachineToUpdate(vmname);
Guests.Add(vm);
}
string hostname = (char)x + "Host";
HostMachineToUpdate host = new HostMachineToUpdate(hostname, Guests);
Hosts.Add(host);
}
I personally don't like the amount of casting used in your traditional solution.
Is all the casting actually needed ?
Wouldn't this (untested) code also do what is required?
// traditional.
Hosts = new List<HostMachineToUpdate>();
foreach (char x in "abcd")
{
List<VirtualMachineToUpdate> Guests = new List<VirtualMachineToUpdate>();
int randomItemNum = new Random().Next(3, 8);
for (int y = 1; y < randomItemNum; y++)
{
Guests.Add(new VirtualMachineToUpdate(x + y.ToString() + "_VM"));
}
Hosts.Add(new HostMachineToUpdate(x + "Host", Guests));
}
I prefer the declarative approach, so something like the first option. But I would rather use the C# syntax. Something vaguely like:
(from x in Enumerable.Range('a', 'e'-'a')
select new HostMachineToUpdate(
(char)x + "_Host",
(from y in Enumerable.Range(1, new Random.Next(3,8))
select new VirtualMachineToUpdate((char)x + y.ToString() + "_VM")).ToList())
.ToList();
It feels close. May be a missing ( or ).
If each of your solutions executes fast enough for your needs, then it is safe to say that the machine cannot tell the difference between these options.
The important consideration devolves down to how expressive or clear is the code to a human reader because in the future someone will have to understand, debug or extend the code. In the above case, try this out. Leave the code alone for two weeks. When you return, decide which of the options is easiest to understand.
For myself this is a reality check. In the past I have been proud of writing some clever code, but in reality a simpler solution was the right solution.

Categories