-
Notifications
You must be signed in to change notification settings - Fork 180
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added VectorTime and BehavioralObserver class for feedback strategy (#…
…799) Co-authored-by: Christine Zhou <[email protected]>
- Loading branch information
1 parent
6bd65eb
commit 2eda040
Showing
7 changed files
with
311 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using PChecker.Runtime.StateMachines; | ||
using PChecker.IO.Logging; | ||
|
||
public class VectorTime | ||
{ | ||
// Dictionary that uses StateMachineId as the key and stores the logical clock as the value | ||
public Dictionary<StateMachineId, int> Clock { get; private set; } | ||
|
||
// The ID of the current state machine | ||
|
||
private StateMachineId stateMachineId; | ||
|
||
public VectorTime(StateMachineId stateMachineId) | ||
{ | ||
this.stateMachineId = stateMachineId; | ||
Clock = new Dictionary<StateMachineId, int>(); | ||
Clock[stateMachineId] = 0; // Initialize the clock for this state machine | ||
} | ||
|
||
// Clone constructor (creates a snapshot of the vector clock) | ||
public VectorTime(VectorTime other) | ||
{ | ||
Clock = new Dictionary<StateMachineId, int>(other.Clock); | ||
} | ||
|
||
// Increment the logical clock for this state machine | ||
public void Increment() | ||
{ | ||
Clock[stateMachineId]++; | ||
} | ||
|
||
// Merge another vector clock into this one | ||
public void Merge(VectorTime otherTime) | ||
{ | ||
foreach (var entry in otherTime.Clock) | ||
{ | ||
StateMachineId otherMachineId = entry.Key; | ||
int otherTimestamp = entry.Value; | ||
|
||
if (Clock.ContainsKey(otherMachineId)) | ||
{ | ||
// Take the maximum timestamp for each state machine | ||
Clock[otherMachineId] = Math.Max(Clock[otherMachineId], otherTimestamp); | ||
} | ||
else | ||
{ | ||
// Add the state machine's timestamp if it doesn't exist in this time | ||
Clock[otherMachineId] = otherTimestamp; | ||
} | ||
} | ||
} | ||
|
||
// Compare this vector clock to another for sorting purposes | ||
// Rturn value: -1 = This vector clock happens after the other, 1 = This vector clock happens before the other, | ||
// 0 = Clocks are equal or concurrent | ||
public int CompareTo(VectorTime other) | ||
{ | ||
bool atLeastOneLess = false; | ||
bool atLeastOneGreater = false; | ||
|
||
foreach (var machineId in Clock.Keys) | ||
{ | ||
int thisTime = Clock[machineId]; | ||
int otherTime = other.Clock.ContainsKey(machineId) ? other.Clock[machineId] : 0; | ||
|
||
if (thisTime < otherTime) | ||
{ | ||
atLeastOneLess = true; | ||
} | ||
else if (thisTime > otherTime) | ||
{ | ||
atLeastOneGreater = true; | ||
} | ||
if (atLeastOneLess && atLeastOneGreater) | ||
{ | ||
return 0; | ||
} | ||
} | ||
if (atLeastOneLess && !atLeastOneGreater) | ||
{ | ||
return -1; | ||
} | ||
if (atLeastOneGreater && !atLeastOneLess) | ||
{ | ||
return 1; | ||
} | ||
return 0; | ||
} | ||
|
||
|
||
public override string ToString() | ||
{ | ||
var elements = new List<string>(); | ||
foreach (var entry in Clock) | ||
{ | ||
elements.Add($"StateMachine {entry.Key.Name}: {entry.Value}"); | ||
} | ||
return $"[{string.Join(", ", elements)}]"; | ||
} | ||
|
||
public override bool Equals(object obj) | ||
{ | ||
if (obj is VectorTime other) | ||
{ | ||
return Clock.OrderBy(x => x.Key).SequenceEqual(other.Clock.OrderBy(x => x.Key)); | ||
} | ||
return false; | ||
} | ||
|
||
public override int GetHashCode() | ||
{ | ||
int hash = 17; | ||
foreach (var entry in Clock) | ||
{ | ||
hash = hash * 31 + entry.Key.GetHashCode(); | ||
hash = hash * 31 + entry.Value.GetHashCode(); | ||
} | ||
return hash; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
166 changes: 166 additions & 0 deletions
166
...PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/BehavioralObserver.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using PChecker.IO.Logging; | ||
using PChecker.Runtime.Events; | ||
|
||
namespace PChecker.Runtime; | ||
|
||
public class BehavioralObserver | ||
{ | ||
private static HashSet<(VectorTime, Event, EventType)> CurrTimeline = new HashSet<(VectorTime, Event, EventType)>(); | ||
private static List<int[]> AllTimeline = new List<int[]>(); | ||
private static TextWriter Logger = new ConsoleLogger(); | ||
// MinHash object with 100 hash functions, check how many of these 100 values are identical between the two sets | ||
private static MinHash minHash = new MinHash(100); | ||
|
||
|
||
public enum EventType | ||
{ | ||
SEND, DEQUEUE | ||
} | ||
|
||
public BehavioralObserver() | ||
{ | ||
CurrTimeline = new HashSet<(VectorTime, Event, EventType)>(); | ||
} | ||
|
||
public static void AddToCurrentTimeline(Event e, EventType t, VectorTime vectorTime) | ||
{ | ||
CurrTimeline.Add((new VectorTime(vectorTime), e, t)); | ||
} | ||
|
||
public static int CalculateDiff(int[] currentSignature, int[] otherSignature) | ||
{ | ||
double similarity = minHash.ComputeSimilarity(currentSignature, otherSignature); | ||
double differenceScore = 1 - similarity; | ||
return (int)(differenceScore * 100); // Scale the difference score (e.g., multiply by 100) | ||
} | ||
|
||
public static int GetUniqueScore(int[] currentSignature) | ||
{ | ||
int scoreSum = 0; | ||
foreach (var otherSignature in AllTimeline) | ||
{ | ||
int score = CalculateDiff(currentSignature, otherSignature); | ||
if (score == 0) | ||
{ | ||
return 0; | ||
} | ||
scoreSum += score; | ||
} | ||
return scoreSum/AllTimeline.Count; | ||
} | ||
|
||
public static void PrintTimeline(List<(VectorTime, Event, EventType)> timeline) | ||
{ | ||
Logger.WriteLine("Global state of all machines:"); | ||
foreach (var entry in timeline) | ||
{ | ||
Logger.WriteLine($"Machine {entry}"); | ||
} | ||
} | ||
|
||
public static List<(VectorTime, Event, EventType)> SortByVectorClock() | ||
{ | ||
List<(VectorTime, Event, EventType)> sortedTimeline = new List<(VectorTime, Event, EventType)>(CurrTimeline); | ||
|
||
// Sort by event name then vector time | ||
sortedTimeline.Sort((x, y) => x.Item2.ToString().CompareTo(y.Item2.ToString())); | ||
sortedTimeline.Sort((x, y) => x.Item1.CompareTo(y.Item1)); | ||
|
||
return sortedTimeline; | ||
} | ||
|
||
public static void NextIter() | ||
{ | ||
if (CurrTimeline.Count == 0) | ||
{ | ||
return; | ||
} | ||
List<(VectorTime, Event, EventType)> SortedCurrTimeline = SortByVectorClock(); | ||
int[] currSignature = minHash.ComputeMinHashSignature(SortedCurrTimeline); | ||
if (AllTimeline.Count == 0) | ||
{ | ||
AllTimeline.Add(currSignature); | ||
return; | ||
} | ||
int uniqueScore = GetUniqueScore(currSignature); | ||
Logger.WriteLine($"----**** UniquenessScore: {uniqueScore}"); | ||
if (uniqueScore != 0) | ||
{ | ||
AllTimeline.Add(currSignature); | ||
} | ||
CurrTimeline = new HashSet<(VectorTime, Event, EventType)>(); | ||
} | ||
} | ||
|
||
public class MinHash | ||
{ | ||
private int numHashFunctions; // Number of hash functions to use | ||
private List<Func<int, int>> hashFunctions; // List of hash functions | ||
|
||
public MinHash(int numHashFunctions) | ||
{ | ||
this.numHashFunctions = numHashFunctions; | ||
this.hashFunctions = new List<Func<int, int>>(); | ||
|
||
System.Random rand = new System.Random(); | ||
for (int i = 0; i < numHashFunctions; i++) | ||
{ | ||
int a = rand.Next(); | ||
int b = rand.Next(); | ||
hashFunctions.Add(x => a * x + b); | ||
} | ||
} | ||
|
||
// Create a MinHash signature for a given set | ||
public int[] ComputeMinHashSignature(List<(VectorTime, Event, BehavioralObserver.EventType)> set) | ||
{ | ||
int[] signature = new int[numHashFunctions]; | ||
|
||
for (int i = 0; i < numHashFunctions; i++) | ||
{ | ||
signature[i] = int.MaxValue; | ||
} | ||
foreach (var element in set) | ||
{ | ||
int elementHash = ComputeElementHash(element); | ||
|
||
for (int i = 0; i < numHashFunctions; i++) | ||
{ | ||
int hashedValue = hashFunctions[i](elementHash); | ||
if (hashedValue < signature[i]) | ||
{ | ||
signature[i] = hashedValue; | ||
} | ||
} | ||
} | ||
return signature; | ||
} | ||
|
||
// Compute a composite hash for the (VectorTime, Event, EventType) tuple | ||
private int ComputeElementHash((VectorTime, Event, BehavioralObserver.EventType) element) | ||
{ | ||
int hash1 = element.Item1.GetHashCode(); | ||
int hash2 = element.Item2.GetHashCode(); | ||
int hash3 = element.Item3.GetHashCode(); | ||
return hash1 ^ hash2 ^ hash3; | ||
} | ||
|
||
// Compute Jaccard similarity based on MinHash signatures | ||
public double ComputeSimilarity(int[] signature1, int[] signature2) | ||
{ | ||
int identicalMinHashes = 0; | ||
|
||
for (int i = 0; i < numHashFunctions; i++) | ||
{ | ||
if (signature1[i] == signature2[i]) | ||
{ | ||
identicalMinHashes++; | ||
} | ||
} | ||
return (double)identicalMinHashes / numHashFunctions; | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters