Prevent scrollbar position from being changed in richtextbox? - c#

I have the following code:
private void HighlightSyntax(string syntax)
{
Regex regex = null;
switch (syntax)
{
case ".xml":
regex = new Regex(#"<\/?[^>\/]*>");
break;
}
if (regex != null)
{
Input.BeginUpdate();
// I want to save scrollbar position here and then restore it
// or maybe even disable it from being changed
int lastIndex = Input.SelectionStart;
int lastLength = Input.SelectionLength;
Input.SelectAll();
// gets matches
var matches = regex.Matches(Input.Text).Cast<Match>().ToArray();
if (matches.Length > 0) // divide into tasks and select all matches
{
Color color = Color.ForestGreen;
int wordsPerTask = 500;
int tasksAmount = (matches.Length / wordsPerTask) + 1;
int start = 0;
int end = matches.Length - 1;
Task[] tasks = new Task[tasksAmount];
for (int i = 0; i < tasksAmount; i++)
{ // dividing
start = matches.Length / tasksAmount * i;
end = matches.Length / tasksAmount * (i + 1) - 1;
var start1 = start;
var end1 = end;
tasks[i] = Task.Run(() => { SelectMatchesInArr(matches, start, end, color); } );
}
if (matches.Length - 1 - end > 0)
SelectMatchesInArr(matches, end + 1, matches.Length - 1, color);
Task.WaitAll(tasks);
}
Input.Select(lastIndex, lastLength);
Input.SelectionColor = Color.Black;
// Restore Input.ScrollBarPosition here
Input.EndUpdate();
}
}
// selects matches from start to end Indexes with Color color.
private void SelectMatchesInArr(Match[] matches, int startIndex, int endIndex, Color color)
{
for (int i = startIndex; i <= endIndex; i++)
{
int selectionStart = Input.SelectionStart;
lock (_locker)
{
Input.Select(matches[i].Index, matches[i].Length);
Input.SelectionColor = color;
Input.DeselectAll();
Input.SelectionStart = selectionStart;
Input.SelectionLength = 0;
}
}
}
It highlights syntax in richtexbox, if regex matches anything related to that syntax. It all worked until I decided to divide selecting into multiple tasks.
After dividing the selection into multiple tasks, my scrollbar position is not stable. Well, I want it to be stable, I don't want it to be changed via code. How do I prevent it from being changed if I have multiple tasks manipulating over richtextbox? What should I do in my situation? Also check comments in the code, they are written in order to help you explain what I want to do.
By the way, the BeginUpdate() and EndUpdate() methods are extension methods that have been taken from here: Hans Passant's derived from richtextbox class

Maybe it would be better to use multithreading only for generating the list of matches and then use them for highlighting?
Also, it seems a bit dangerous to modify UI in multiple threads without any synchronization since it's possible that one thread would call 'Input.Select' and the other one 'Input.DeselectAll' before the first one will set the color.
Applying UI changes in one thread would eliminate that possibility.

Related

Parallel.ForEach is exited before it completes

Well, I'm using Parallel ForEach to process a very big array of Colors (35M of indexers).
I'm using Partitioner.Create to do this with perfomance. But something unexpected is happening:
private Color32[] MainGeneration(Color32[] proccesed, Color32[] dupe, int width, int height)
{
int i = 0;
Parallel.ForEach(Partitioner.Create(0, totalIndexes), item =>
{
int x = i % width;
int y = height - i / width - 1;
dupe[i] = (UnityEngine.Color)MapIteration((Color)((Color)(UnityEngine.Color)proccesed[i]).Clone(), i, x, y)
++i;
if (i % updateInterlockedEvery == 0)
{
++currentIndex; //Interlocked.Increment(ref currentIndex);
}
});
// If Parallel.ForEach is blocking, why this is outputting me 12 when total indexes value is 35.000.000?
Debug.Log(i);
return dupe;
}
As I wroted on the comment, why is this happening?
The expected behaviour of this, is to process a large image using parallelism, not only a small piece.
processed contains the full image.
dupe contains a empty array that will be completed on each iteration.
I do all this in the local scope to avoid heap problems.
Don't you want something like, Fiddle Here
using System.Collections.Concurrent;
using System.Threading.Tasks;
using UnityEngine;
public class Program
{
private void MainGeneration(
Color32[] source,
Color32[] target,
int width,
int height)
{
Parallel.ForEach(Partitioner.Create(source, true)
.GetOrderableDynamicPartitions(), colorItem =>
{
var i = colorItem.Key;
var color = colorItem.Value;
var x = i % width;
var y = height - i / width - 1;
target[i] = this.Map(color, i, x, y);
});
}
private Color32 Map(Color32 color, long i, long x, long y)
{
return color;
}
}
++i; is in fact shorthand for something like this:
temp = i + 1;
i = temp;
Luckily you are using int not long, so at least the i = temp; assignment is atomic, the explanation is easier :)
If two threads are both doing ++i; something like this can happen (only two threads considered for simplicity):
//Let's say i == 0
Thread 2 calculates i + 1 //== 1
Thread 1 calculates i + 1 //== 1
Thread 1 sets i = 1;
Thread 2 sets i = 1;
So here you would probably expect i to be 2, but in fact it is 1 by the end of this.
If you want to increment i in a threadsafe manner you can do:
Interlocked.Increment(ref i);
As pointed in your code for currentIndex which should be also calculated like this.
I see another issue with the code given the huge discrepancy in numbers. Exceptions that happen outside of the main thread are not reported to/on the main thread if the IsBackGround property of the thread is true. To guard against this, you should try/catch the inner block in the foreach to also count exceptions in a similar way.
Or even better, get a list of exceptions in a ConcurrentQueue/ConcurrentBag :
// Use ConcurrentQueue to enable safe enqueueing from multiple threads.
var exceptions = new ConcurrentQueue<Exception>();
// Execute the complete loop and capture all exceptions.
Parallel.ForEach(data, d =>
{
try
{
// Cause a few exceptions, but not too many.
if (d < 3)
throw new ArgumentException($"Value is {d}. Value must be greater than or equal to 3.");
else
Console.Write(d + " ");
}
// Store the exception and continue with the loop.
catch (Exception e)
{
exceptions.Enqueue(e);
}
});
Console.WriteLine();
// Throw the exceptions here after the loop completes.
if (exceptions.Count > 0) throw new AggregateException(exceptions);
(source: https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-handle-exceptions-in-parallel-loops)

Permutation on array of type "Location", from GoogleMapsAPI NuGet Package

this is my very first post here on StackOverflow so please tell me if I did anything wrong, also english is not my native language, forgive me if there is any gramatical errors.
My question is how can I permutate the items of an array of type "Location", I need to get all possible permutations of waypoints given by the user to then calculate the best route based on time or distance. (I don't want to use the normal route calculation)
I've searched for algorithms but all of them when I put the array of type "Location[]" in the function's parameter I get the error that the object needs to be IEnumerable and I don't know how to convert to that if is even possible, I never worked with IEnumerable.
If it is of any help this is my code for calculating the route:
//Gets the waypoints from a listBox provided by the user, "mode" selects between best time and best distance
//backgroundworker so the UI dont freezes, and return the optimal waypoint order
public Location[] CalcularRota(Location[] waypoints, int mode, BackgroundWorker work, DoWorkEventArgs e)
{
//Declarations
string origem = "";
string destino = "";
Rota[] prop = new Rota[100]; //this index is the number of times the algorithm will be executed, more equals accuracy but much more time to complete
Rota bestDist = new Rota();
Rota bestTime = new Rota();
DirectionService serv = new DirectionService();
DirectionRequest reqs = new DirectionRequest();
DirectionResponse resp;
Random rnd = new Random();
Location[] rndWays;
int dist = 0;
int ti = 0;
bestDist.Distance = 1000000000; //put higher values for the first comparation to be true (end of code)
bestTime.Time = 1000000000;
if (waypoints != null)
{
reqs.Sensor = false;
reqs.Mode = TravelMode.driving;
for (int i = 0; i < prop.Length; i++) //initializes prop
prop[i] = new Rota();
for (int i = 0; i < prop.Length; i++)
{
rndWays = waypoints.OrderBy(x => rnd.Next()).ToArray(); //randomizes the order, I want to get all permutations and then test
//but I dont know how so I've been using randomized
dist = ti = 0;
origem = prop[0].ToString(); //save this particular waypoint's origin and destination
destino = prop[1].ToString();
reqs.Origin = origem;
reqs.Destination = destino;
if (waypoints.Length > 0)
reqs.Waypoints = rndWays;
resp = serv.GetResponse(reqs); //request the route with X order of waypoints to google
if (resp.Status == ServiceResponseStatus.Ok) //wait the response otherwise the program crashes
{
for (int j = 0; j < resp.Routes[0].Legs.Length; j++) //gets the distance and time of this particular order
{
ti += int.Parse(resp.Routes[0].Legs[j].Duration.Value);
dist += int.Parse(resp.Routes[0].Legs[j].Distance.Value);
}
}
prop[i].Origem = origem; //saves this waypoints order details for further comparison
prop[i].Destino = destino;
prop[i].Distance = dist;
prop[i].Time = ti;
prop[i].Order = rndWays;
work.ReportProgress(i); //report the progress
}
for (int i = 0; i < prop.Length; i++) //gets the best distance and time
{
if (bestDist.Distance > prop[i].Distance)
{
bestDist.Distance = prop[i].Distance;
bestDist.Time = prop[i].Time;
bestDist.Order = prop[i].Order;
bestDist.Origem = prop[i].Origem;
bestDist.Destino = prop[i].Destino;
}
if (bestTime.Time > prop[i].Time)
{
bestTime.Distance = prop[i].Distance;
bestTime.Time = prop[i].Time;
bestTime.Order = prop[i].Order;
bestTime.Origem = prop[i].Origem;
bestTime.Destino = prop[i].Destino;
}
}
if (bestDist.Order == bestTime.Order) //if the same waypoint order has the same time and distance
return bestDist.Order; // returns whatever bestDist.Order or bestTime.Order
else if (bestDist.Order != bestTime.Order) //if different returns corresponding to the mode selected
{
if (mode == 1) return bestDist.Order;
if (mode == 2) return bestTime.Order;
}
}
return null;
}
What I want is to permutate the waypoints given and test each permutation, I've been struggling with this for a time, if u guys could help me with any way possible would be great.
Ty.
EDIT.
I found this function here on StackOverflow:
public static bool NextPermutation<T>(T[] elements) where T : IComparable<T>
{
var count = elements.Length;
var done = true;
for (var i = count - 1; i > 0; i--)
{
var curr = elements[i];
// Check if the current element is less than the one before it
if (curr.CompareTo(elements[i - 1]) < 0)
{
continue;
}
// An element bigger than the one before it has been found,
// so this isn't the last lexicographic permutation.
done = false;
// Save the previous (bigger) element in a variable for more efficiency.
var prev = elements[i - 1];
// Have a variable to hold the index of the element to swap
// with the previous element (the to-swap element would be
// the smallest element that comes after the previous element
// and is bigger than the previous element), initializing it
// as the current index of the current item (curr).
var currIndex = i;
// Go through the array from the element after the current one to last
for (var j = i + 1; j < count; j++)
{
// Save into variable for more efficiency
var tmp = elements[j];
// Check if tmp suits the "next swap" conditions:
// Smallest, but bigger than the "prev" element
if (tmp.CompareTo(curr) < 0 && tmp.CompareTo(prev) > 0)
{
curr = tmp;
currIndex = j;
}
}
// Swap the "prev" with the new "curr" (the swap-with element)
elements[currIndex] = prev;
elements[i - 1] = curr;
// Reverse the order of the tail, in order to reset it's lexicographic order
for (var j = count - 1; j > i; j--, i++)
{
var tmp = elements[j];
elements[j] = elements[i];
elements[i] = tmp;
}
// Break since we have got the next permutation
// The reason to have all the logic inside the loop is
// to prevent the need of an extra variable indicating "i" when
// the next needed swap is found (moving "i" outside the loop is a
// bad practice, and isn't very readable, so I preferred not doing
// that as well).
break;
}
// Return whether this has been the last lexicographic permutation.
return done;
}
The usage is:
NextPermutation(array);
Doing this and putting my array (rndWays) as overload I get the following error:
The type 'Google.Maps.Location' cannot be used as type parameter 'T' in the generic type or method 'Form1.NextPermutation< T >(T[])'. There is no implicit reference conversion from 'Google.Maps.Location' to 'System.IComparable< Google.Maps.Location >'.
The problem is that Location does not implement the IComparable interface.
Change:
public static bool NextPermutation<T>(T[] elements) where T : IComparable<T>
to:
public static bool NextPermutation(Location[] elements)
And replace each CompareTo() with your own comparison function.

Why when making a loop it's all the time reset to 0 on next iterations?

I have a method with some loops inside:
private void RefreshListBox()
{
int i = 0, j = 0, index, count;
Boolean bl = false;
index = listBox1.SelectedIndex;
count = windowsHandles.Count;
for (i = 0; i < count; i++)
{
if (!Constants.IsWindow(windowsHandles[j]))
{
windowsHandles.RemoveAt(j);
windowsText.RemoveAt(j);
windowsBitmaps.RemoveAt(j);
rectanglesList.RemoveAt(j);
isCroppedList.RemoveAt(j);
canDrawNormallyList.RemoveAt(j);
if (j < index)
{
index--;
}
else if (j == index)
{
}
else
{
}
}
else { j++; }
}
if (index == windowsHandles.Count)
{
index--;
}
for (int x = 0; x < windows.Count; x++)
{
for (j = 0; j < windowsHandles.Count; j++)
{
if (windowsHandles[j] == windows[x].Handle) { bl = true; break; }
}
if (bl == false && Constants.IsIconic(windows[x].Handle))
{
windowsHandles.Add(windows[x].Handle);
windowsText.Add(windows[x].Title);
windowsBitmaps.Add(null);
rectanglesList.Add(new Rectangle(0, 0, 0, 0));
isCroppedList.Add(false);
canDrawNormallyList.Add(false);
}
bl = false;
}
if (windowsHandles.Count > 0 && index == -1)
{
index = 0;
}
if (listBox1.Items.Count > 0) { listBox1.Items.Clear(); }
for (i = 0; i < windowsHandles.Count; i++)
{
listBox1.Items.Add(windowsText[i]);
}
if (index != -1)
{
listBox1.SelectedIndex = index;
}
textBoxIndex.Text = windowsHandles.Count.ToString();
drawPicBox(index);
}
private void listBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
var item = listBox1.IndexFromPoint(e.Location);
if (item >= 0)
{
listBox1.SelectedIndex = item;
drawPicBox(listBox1.SelectedIndex);
}
}
}
The problem start when it's getting to the loop at this line:
for (int x = 0; x < windows.Count; x++)
The Count of windows List is 21 in this case.
Then it's entering first time but if i put a break point on this line and click continue all the time i see that x is 0.
When i put a break point on this line:
windowsHandles.Add(windows[x].Handle);
It stop there each time i click on continue but then i see that the variable x it's value is 20 all the time. And the List windowsHandles contain only 1 item.
Then i put a break point on the line:
listBox1.Items.Add(windowsText[i]);
And when i make continue it stop on the line but even if it does the line there are no items on the listBox1.
If i don't use any break points and just make continue to let it run it's never show/get to the form it's like stuck somewhere in this method can't figure out where and why.
In the constructor i'm calling two methods.
First GetWindows then RefreshList
GetWindows();
RefreshListBox();
In GetWindows:
private List<Window> windows = new List<Window>();
private void GetWindows()
{
windows = new List<Window>();
Constants.EnumWindows(Callback, 0);
}
private bool Callback(IntPtr hwnd, int lParam)
{
try
{
if (this.Handle != hwnd && (Constants.GetWindowLongA(hwnd, Constants.GWL_STYLE) & Constants.TARGETWINDOW) == Constants.TARGETWINDOW)
{
StringBuilder sb = new StringBuilder(100);
Constants.GetWindowText(hwnd, sb, sb.Capacity);
Window t = new Window();
t.Handle = hwnd;
t.Title = sb.ToString();
windows.Add(t);
}
}
catch(Exception err)
{
StreamWriter w = new StreamWriter(#"e:\errors.txt");
w.Write(err.ToString());
w.Close();
}
return true;
}
In the end of the GetWindows operation i see that windows contain 21 items.
The problem seems to be somewhere in the RefreshList method but i can't figure out where is the problem.
The goal of all this in the end is to add all the items in windowsText to the listBox1.
I just noticed something else:
windowsHandles.Add(windows[x].Handle);
windowsText.Add(windows[x].Title);
windowsBitmaps.Add(null); // <------
rectanglesList.Add(new Rectangle(0, 0, 0, 0));
isCroppedList.Add(false);
canDrawNormallyList.Add(false);
Is this a correct guess - The reason you're adding a null to windowsBitmaps is so that all six of these collections stay in sync. The items across each collection are related somehow if they have the same index.
It would be much easier if you created one class with properties for windowsHandle, windowsText, windowsBitmaps, etc, and then had a collection of that type. That way instead of managing six collections and trying to keep them in sync you only have one.
This isn't a direct answer, but I think it's a necessary step if you're going to get to the answer: break this up into smaller methods.
You could start with the loops. You could put each of those loops in a separate method and name the method very clearly so that it indicates what it's doing and what it's doing it to. (It might even be worthwhile to put some of the functions in separate classes.)
One of the reasons is that no one - not you or the programmer who works on this later - can expect to be able to hold the complexity of one long method in their head and follow through 'what if this happens, what if that happens.'
Same thing for variable names. It's okay if variable names and method names are long if they help make it clear what they are for. I find myself seeing x and having to scroll back up to see what x is, and then I lose track of where I was.
I know that's not a direct answer. But if you do that then the answer will likely be easier to see. If you break it up into smaller functions (or even write separate classes) then you can also write unit tests. That way instead of running the whole thing from top to bottom you can just test one part at a time.
More directly related
Somewhat more directly related to the code: If you do need to iterate through a collection and possibly remove items as you go, it's better to start from the Count and work backwards. That way your index stays in bounds.
An even easier way is to use Linq to query the elements and create a new collection. For example
Thing[] arrayOfSomething = GetAnArrayOfSomething();
var arrayWithElementsRemoved = arrayOfSomething.Where(
item => !item.DeleteThisOne).ToArray();
The second statement takes an array of Thing and returns a new array containing only the ones where DeleteThisOne is false. It's all in one statement, no looping or bounds to worry about.

Delay in a WinForms app without using "await Task.Delay(x)"

I'm creating a poker app and i want to make some sort of simulation of the throwing of the cards effect and to do that I currently use await Task.Delay(x); However this requires async Task and if i switch this method where i do the task.delay(x) to async i will have to change at least 5-6 more into async as well. I suppose this is fine for someone that understand the exact way the asynchronus works. Currently im getting a lot of logic errors simply because i obviously don't know how async and await operators work.. In other words I'm newbie, and is there any alternative to this exact line await Task.Delay(x); I wont use anything else that is connected to async just this line.
Here's the code :
private async Task Shuffle()
{
Bitmap refreshBackImage = new Bitmap(getBack);
bCall.Enabled = false;
bRaise.Enabled = false;
bFold.Enabled = false;
bCheck.Enabled = false;
MaximizeBox = false;
MinimizeBox = false;
bool check = false;
horizontal = tbChips.Left - _settings.Width * 2 - 15;
vertical = pbTimer.Top - _settings.Height - (_settings.Height) / 7;
RNGCrypto random = new RNGCrypto();
for (i = ImgLocation.Length; i > 0; i--)
{
int j = random.Next(i);
string k = ImgLocation[j];
ImgLocation[j] = ImgLocation[i - 1];
ImgLocation[i - 1] = k;
}
for (i = 0; i < 17; i++)
{
Deck[i] = Image.FromFile(ImgLocation[i]);
string[] charsToRemove = { getCards, ".png", "\\" };
foreach (string c in charsToRemove)
{
ImgLocation[i] = ImgLocation[i].Replace(c, string.Empty);
}
Reserve[i] = int.Parse(ImgLocation[i]) - 1;
Holder[i] = new PictureBox
{
SizeMode = PictureBoxSizeMode.StretchImage,
Height = _settings.Height,
Width = _settings.Width
};
Controls.Add(Holder[i]);
Holder[i].Name = "pb" + i;
await Task.Delay(150);
#region Throwing Cards
SetPlayers(Player, i, ref check, 560, 470, refreshBackImage);
SetPlayers(Bot1, i, ref check, 15, 420, refreshBackImage);
SetPlayers(Bot2, i, ref check, 75, 65, refreshBackImage);
SetPlayers(Bot3, i, ref check, 590, 25, refreshBackImage);
SetPlayers(Bot4, i, ref check, 1115, 65, refreshBackImage);
SetPlayers(Bot5, i, ref check, 1160, 420, refreshBackImage);
if (i >= 12)
{
Holder[12].Tag = Reserve[12];
if (i > 12) Holder[13].Tag = Reserve[13];
if (i > 13) Holder[14].Tag = Reserve[14];
if (i > 14) Holder[15].Tag = Reserve[15];
if (i > 15)
{
Holder[16].Tag = Reserve[16];
}
if (!check)
{
horizontal = 410;
vertical = 265;
}
check = true;
if (Holder[i] != null)
{
Holder[i].Anchor = AnchorStyles.None;
Holder[i].Image = refreshBackImage;
//Holder[i].Image = Deck[i];
Holder[i].Location = new Point(horizontal, vertical);
horizontal += 110;
}
}
#endregion
Bot1 = (Bot)FoldedPlayer(Bot1);
Bot2 = (Bot)FoldedPlayer(Bot2);
Bot3 = (Bot)FoldedPlayer(Bot3);
Bot4 = (Bot)FoldedPlayer(Bot4);
Bot5 = (Bot)FoldedPlayer(Bot5);
if (i == 16)
{
if (!restart)
{
MaximizeBox = true;
MinimizeBox = true;
}
Turns();
}
}
Ending();
}
For things like animations, you might want the System.Windows.Forms.Timer component, which raises a periodic event.
You can configure the interval as well as temporarily disabling it entirely.
Note that after the delay, you'll be back to the top of the handler function... it doesn't automatically keep track of where you are in your sequence the way the await keyword automatically resumes at the next line. So you'll need some counter or such to let you know what step of the animation is coming next.
I'm not sure if you want to do the async, because it wont come back until it's complete. Meaning if you want something timed. Async will have some trouble providing this for you. Because you'll either have to wait for the response which may be an issue. Especially if its a game. Watch how the async functions in debug and you'll understand. An event trigger, or just a timed event will work much better because you'll have the control of when it triggers or how a long you wait for the event. This will get rid of your delay all together or it should.
In your case, a simple trigger event at the time, will display the throwing of cards, and once finished will continue on with your function. That's simple terms, you may have to do a few things like waiting until that trigger is finished. Either way there is a ton of information regarding events. Have a look before you go for async. Since it's forms you can do it however you please, if it for windows phone or other types of systems some require async only.
this should help:
https://msdn.microsoft.com/en-us/library/wkzf914z(v=vs.90).aspx

Thread safety Parallel.For c#

im frenchi so sorry first sorry for my english .
I have an error on visual studio (index out of range) i have this problem only with a Parallel.For not with classic for.
I think one thread want acces on my array[i] and another thread want too ..
It's a code for calcul Kmeans clustering for building link between document (with cosine similarity).
more information :
IndexOutOfRange is on similarityMeasure[i]=.....
I have a computer with 2 Processor (12logical)
with classic for , cpu usage is 9-14% , time for 1 iteration=9min..
with parallel.for , cpu usage is 70-90% =p, time for 1 iteration =~1min30
Sometimes it works longer before generating an error
My function is :
private static int FindClosestClusterCenter(List<Centroid> clustercenter, DocumentVector obj)
{
float[] similarityMeasure = new float[clustercenter.Count()];
float[] copy = similarityMeasure;
object sync = new Object();
Parallel.For(0, clustercenter.Count(), (i) => //for(int i = 0; i < clustercenter.Count(); i++) Parallel.For(0, clustercenter.Count(), (i) => //
{
similarityMeasure[i] = SimilarityMatrics.FindCosineSimilarity(clustercenter[i].GroupedDocument[0].VectorSpace, obj.VectorSpace);
});
int index = 0;
float maxValue = similarityMeasure[0];
for (int i = 0; i < similarityMeasure.Count(); i++)
{
if (similarityMeasure[i] > maxValue)
{
maxValue = similarityMeasure[i];
index = i;
}
}
return index;
}
My function is call here :
do
{
prevClusterCenter = centroidCollection;
DateTime starttime = DateTime.Now;
foreach (DocumentVector obj in documentCollection)//Parallel.ForEach(documentCollection, parallelOptions, obj =>//foreach (DocumentVector obj in documentCollection)
{
int ind = FindClosestClusterCenter(centroidCollection, obj);
resultSet[ind].GroupedDocument.Add(obj);
}
TimeSpan tempsecoule = DateTime.Now.Subtract(starttime);
Console.WriteLine(tempsecoule);
//Console.ReadKey();
InitializeClusterCentroid(out centroidCollection, centroidCollection.Count());
centroidCollection = CalculMeanPoints(resultSet);
stoppingCriteria = CheckStoppingCriteria(prevClusterCenter, centroidCollection);
if (!stoppingCriteria)
{
//initialisation du resultat pour la prochaine itération
InitializeClusterCentroid(out resultSet, centroidCollection.Count);
}
} while (stoppingCriteria == false);
_counter = counter;
return resultSet;
FindCosSimilarity :
public static float FindCosineSimilarity(float[] vecA, float[] vecB)
{
var dotProduct = DotProduct(vecA, vecB);
var magnitudeOfA = Magnitude(vecA);
var magnitudeOfB = Magnitude(vecB);
float result = dotProduct / (float)Math.Pow((magnitudeOfA * magnitudeOfB),2);
//when 0 is divided by 0 it shows result NaN so return 0 in such case.
if (float.IsNaN(result))
return 0;
else
return (float)result;
}
CalculMeansPoint :
private static List<Centroid> CalculMeanPoints(List<Centroid> _clust)
{
for (int i = 0; i < _clust.Count(); i++)
{
if (_clust[i].GroupedDocument.Count() > 0)
{
for (int j = 0; j < _clust[i].GroupedDocument[0].VectorSpace.Count(); j++)
{
float total = 0;
foreach (DocumentVector vspace in _clust[i].GroupedDocument)
{
total += vspace.VectorSpace[j];
}
_clust[i].GroupedDocument[0].VectorSpace[j] = total / _clust[i].GroupedDocument.Count();
}
}
}
return _clust;
}
You may have some side effects in FindCosineSimilarity, make sure it does not modify any field or input parameter. Example: resultSet[ind].GroupedDocument.Add(obj);. If resultSet is not a reference to locally instantiated array, then that is a side effect.
That may fix it. But FYI you could use AsParallel for this rather than Parallel.For:
similarityMeasure = clustercenter
.AsParallel().AsOrdered()
.Select(c=> SimilarityMatrics.FindCosineSimilarity(c.GroupedDocument[0].VectorSpace, obj.VectorSpace))
.ToArray();
You realize that if you synchronize the whole Content of the Parallel-For, it's just the same as having a normal synchrone for-loop, right? Meaning the code as it is doesnt do anything in parallel, so I dont think you'll have any Problems with concurrency. My guess from what I can tell is clustercenter[i].GroupedDocument is propably an empty Array.

Categories

Resources