From eb8588df9f9a8fbaad7d28f8364fa3477a46372a Mon Sep 17 00:00:00 2001 From: Arunima Chaudhuri Date: Sun, 21 Jan 2024 01:27:17 +0530 Subject: [PATCH 01/21] Introduce 'maliciousNode' parameter Signed-off-by: Arunima Chaudhuri --- DAS/results.py | 12 +++++++ DAS/shape.py | 4 ++- DAS/simulator.py | 21 ++++++++++-- DAS/validator.py | 62 ++++++++++++++++++++++++----------- DAS/visualizor.py | 83 +++++++++++++++++++++++++++++++++++++++++++---- smallConf.py | 21 +++++++----- 6 files changed, 165 insertions(+), 38 deletions(-) diff --git a/DAS/results.py b/DAS/results.py index 76d96d1..628e8a8 100644 --- a/DAS/results.py +++ b/DAS/results.py @@ -16,6 +16,18 @@ class Result: self.tta = -1 self.missingVector = [] self.metrics = {} + self.amImalicious = [0] * shape.numberNodes + self.msgSentCount = [0] * shape.numberNodes + self.msgRecvCount = [0] * shape.numberNodes + self.sampleRecvCount = [0] * shape.numberNodes + + def copyValidators(self, validators): + """Copy information from simulator.validators to result.""" + for i in range(0,self.shape.numberNodes): + self.amImalicious[i] = validators[i].amImalicious + self.msgSentCount[i] = validators[i].msgSentCount + self.msgRecvCount[i] = validators[i].msgRecvCount + self.sampleRecvCount[i] = validators[i].sampleRecvCount def populate(self, shape, config, missingVector): """It populates part of the result data inside a vector.""" diff --git a/DAS/shape.py b/DAS/shape.py index 9f6d573..109bf97 100644 --- a/DAS/shape.py +++ b/DAS/shape.py @@ -3,13 +3,14 @@ class Shape: """This class represents a set of parameters for a specific simulation.""" - def __init__(self, blockSize, numberNodes, failureModel, failureRate, class1ratio, chi, vpn1, vpn2, netDegree, bwUplinkProd, bwUplink1, bwUplink2, run): + def __init__(self, blockSize, numberNodes, failureModel, failureRate, maliciousNodes, class1ratio, chi, vpn1, vpn2, netDegree, bwUplinkProd, bwUplink1, bwUplink2, run): """Initializes the shape with the parameters passed in argument.""" self.run = run self.numberNodes = numberNodes self.blockSize = blockSize self.failureModel = failureModel self.failureRate = failureRate + self.maliciousNodes = maliciousNodes self.netDegree = netDegree self.class1ratio = class1ratio self.chi = chi @@ -36,6 +37,7 @@ class Shape: shastr += "-bwup2-"+str(self.bwUplink2) shastr += "-nd-"+str(self.netDegree) shastr += "-r-"+str(self.run) + shastr += "-mn-"+str(self.maliciousNodes) return shastr def setSeed(self, seed): diff --git a/DAS/simulator.py b/DAS/simulator.py index 147d499..faffdff 100644 --- a/DAS/simulator.py +++ b/DAS/simulator.py @@ -70,7 +70,14 @@ class Simulator: assignedRows = [] assignedCols = [] + maliciousNodesCount = int((self.shape.maliciousNodes / 100) * self.shape.numberNodes) for i in range(self.shape.numberNodes): + if i==0: + amImalicious_value = 0 + elif i < maliciousNodesCount+1: + amImalicious_value = 1 + else: + amImalicious_value = 0 if self.config.evenLineDistribution: if i < int(lightVal/self.shape.vpn1): # First start with the light nodes start = i *self.shape.chi*self.shape.vpn1 @@ -81,7 +88,7 @@ class Simulator: end = offset+((j+1)*self.shape.chi*self.shape.vpn2) r = rows[start:end] c = columns[start:end] - val = Validator(i, int(not i!=0), self.logger, self.shape, self.config, r, c) + val = Validator(i, int(not i!=0), amImalicious_value, self.logger, self.shape, self.config, r, c) self.logger.debug("Node %d has row IDs: %s" % (val.ID, val.rowIDs), extra=self.format) self.logger.debug("Node %d has column IDs: %s" % (val.ID, val.columnIDs), extra=self.format) assignedRows = assignedRows + list(r) @@ -90,7 +97,7 @@ class Simulator: self.nodeColumns.append(val.columnIDs) else: - val = Validator(i, int(not i!=0), self.logger, self.shape, self.config) + val = Validator(i, int(not i!=0), amImalicious_value, self.logger, self.shape, self.config) if i == self.proposerID: val.initBlock() else: @@ -229,6 +236,7 @@ class Simulator: missingVector = [] progressVector = [] trafficStatsVector = [] + malicious_nodes_not_added_count = 0 steps = 0 while(True): missingVector.append(missingSamples) @@ -298,6 +306,14 @@ class Simulator: break steps += 1 + for i in range(0,self.shape.numberNodes): + if not self.validators[i].amIaddedToQueue : + malicious_nodes_not_added_count += 1 + + self.logger.debug("Number of malicious nodes not added to the send queue: %d" % malicious_nodes_not_added_count, extra=self.format) + malicious_nodes_not_added_percentage = (malicious_nodes_not_added_count * 100)/(self.shape.numberNodes) + self.logger.debug("Percentage of malicious nodes not added to the send queue: %d" % malicious_nodes_not_added_percentage, extra=self.format) + progress = pd.DataFrame(progressVector) if self.config.saveRCdist: self.result.addMetric("rowDist", self.distR) @@ -305,5 +321,6 @@ class Simulator: if self.config.saveProgress: self.result.addMetric("progress", progress.to_dict(orient='list')) self.result.populate(self.shape, self.config, missingVector) + self.result.copyValidators(self.validators) return self.result diff --git a/DAS/validator.py b/DAS/validator.py index 4e8d350..eaf7686 100644 --- a/DAS/validator.py +++ b/DAS/validator.py @@ -38,7 +38,7 @@ class Validator: """It returns the validator ID.""" return str(self.ID) - def __init__(self, ID, amIproposer, logger, shape, config, rows = None, columns = None): + def __init__(self, ID, amIproposer, amImalicious, logger, shape, config, rows = None, columns = None): """It initializes the validator with the logger shape and rows/columns. If rows/columns are specified these are observed, otherwise (default) @@ -54,6 +54,12 @@ class Validator: self.receivedQueue = deque() self.sendQueue = deque() self.amIproposer = amIproposer + self.amImalicious = amImalicious + self.amIaddedToQueue = 0 + self.msgSentCount = 0 + self.msgRecvCount = 0 + self.sampleSentCount = 0 + self.sampleRecvCount = 0 self.logger = logger if self.shape.chi < 1: self.logger.error("Chi has to be greater than 0", extra=self.format) @@ -197,8 +203,10 @@ class Validator: if not self.receivedBlock.getSegment(rID, cID): self.logger.trace("Recv new: %d->%d: %d,%d", src, self.ID, rID, cID, extra=self.format) self.receivedBlock.setSegment(rID, cID) + self.sampleRecvCount += 1 if self.perNodeQueue or self.perNeighborQueue: self.receivedQueue.append((rID, cID)) + self.msgRecvCount += 1 else: self.logger.trace("Recv DUP: %d->%d: %d,%d", src, self.ID, rID, cID, extra=self.format) self.statsRxDupInSlot += 1 @@ -206,17 +214,23 @@ class Validator: def addToSendQueue(self, rID, cID): """Queue a segment for forwarding.""" - if self.perNodeQueue: + if self.perNodeQueue and not self.amImalicious: self.sendQueue.append((rID, cID)) + self.amIaddedToQueue = 1 + self.msgSentCount += 1 - if self.perNeighborQueue: + if self.perNeighborQueue and not self.amImalicious: if rID in self.rowIDs: for neigh in self.rowNeighbors[rID].values(): neigh.sendQueue.append(cID) + self.amIaddedToQueue = 1 + self.msgSentCount += 1 if cID in self.columnIDs: for neigh in self.columnNeighbors[cID].values(): neigh.sendQueue.append(rID) + self.amIaddedToQueue = 1 + self.msgSentCount += 1 def receiveRowsColumns(self): """Finalize time step by merging newly received segments in state.""" @@ -233,11 +247,14 @@ class Validator: neigh.received |= neigh.receiving neigh.receiving.setall(0) + for rID, cID in self.receivedQueue: + self.msgRecvCount += 1 # add newly received segments to the send queue if self.perNodeQueue or self.perNeighborQueue: while self.receivedQueue: (rID, cID) = self.receivedQueue.popleft() - self.addToSendQueue(rID, cID) + if not self.amImalicious: + self.addToSendQueue(rID, cID) def updateStats(self): """It updates the stats related to sent and received data.""" @@ -269,7 +286,7 @@ class Validator: def checkSendSegmentToNeigh(self, rID, cID, neigh): """Check and send a segment to a neighbor if needed.""" - if self.checkSegmentToNeigh(rID, cID, neigh): + if self.checkSegmentToNeigh(rID, cID, neigh) and not self.amImalicious: self.sendSegmentToNeigh(rID, cID, neigh) return True else: @@ -286,14 +303,16 @@ class Validator: if rID in self.rowIDs: for _, neigh in shuffledDict(self.rowNeighbors[rID], self.shuffleNeighbors): - self.checkSendSegmentToNeigh(rID, cID, neigh) + if not self.amImalicious: + self.checkSendSegmentToNeigh(rID, cID, neigh) if self.statsTxInSlot >= self.bwUplink: return if cID in self.columnIDs: for _, neigh in shuffledDict(self.columnNeighbors[cID], self.shuffleNeighbors): - self.checkSendSegmentToNeigh(rID, cID, neigh) + if not self.amImalicious: + self.checkSendSegmentToNeigh(rID, cID, neigh) if self.statsTxInSlot >= self.bwUplink: return @@ -318,19 +337,20 @@ class Validator: # collect and shuffle for rID, neighs in self.rowNeighbors.items(): for neigh in neighs.values(): - if (neigh.sendQueue): + if (neigh.sendQueue) and not self.amImalicious: queues.append((0, rID, neigh)) for cID, neighs in self.columnNeighbors.items(): for neigh in neighs.values(): - if (neigh.sendQueue): + if (neigh.sendQueue) and not self.amImalicious: queues.append((1, cID, neigh)) for dim, lineID, neigh in shuffled(queues, self.shuffleQueues): - if dim == 0: - self.checkSendSegmentToNeigh(lineID, neigh.sendQueue.popleft(), neigh) - else: - self.checkSendSegmentToNeigh(neigh.sendQueue.popleft(), lineID, neigh) + if not self.amImalicious: + if dim == 0: + self.checkSendSegmentToNeigh(lineID, neigh.sendQueue.popleft(), neigh) + else: + self.checkSendSegmentToNeigh(neigh.sendQueue.popleft(), lineID, neigh) progress = True if self.statsTxInSlot >= self.bwUplink: return @@ -450,22 +470,24 @@ class Validator: """ Send as much as we can in the timestep, limited by bwUplink.""" # process node level send queue - self.processSendQueue() + if not self.amImalicious: + self.processSendQueue() if self.statsTxInSlot >= self.bwUplink: return # process neighbor level send queues in shuffled breadth-first order - self.processPerNeighborSendQueue() + if not self.amImalicious: + self.processPerNeighborSendQueue() if self.statsTxInSlot >= self.bwUplink: return # process possible segments to send in shuffled breadth-first order - if self.segmentShuffleScheduler: + if self.segmentShuffleScheduler and not self.amImalicious: self.runSegmentShuffleScheduler() if self.statsTxInSlot >= self.bwUplink: return - if self.dumbRandomScheduler: + if self.dumbRandomScheduler and not self.amImalicious: self.runDumbRandomScheduler() if self.statsTxInSlot >= self.bwUplink: return @@ -497,7 +519,8 @@ class Validator: for i in range(len(rep)): if rep[i]: self.logger.trace("Rep: %d,%d", id, i, extra=self.format) - self.addToSendQueue(id, i) + if not self.amImalicious: + self.addToSendQueue(id, i) # self.statsRepairInSlot += rep.count(1) def restoreColumns(self): @@ -515,7 +538,8 @@ class Validator: for i in range(len(rep)): if rep[i]: self.logger.trace("Rep: %d,%d", i, id, extra=self.format) - self.addToSendQueue(i, id) + if not self.amImalicious: + self.addToSendQueue(i, id) # self.statsRepairInSlot += rep.count(1) def checkStatus(self): diff --git a/DAS/visualizor.py b/DAS/visualizor.py index cb3c5d9..fb582e9 100644 --- a/DAS/visualizor.py +++ b/DAS/visualizor.py @@ -6,16 +6,20 @@ import os def plotData(conf): plt.clf() fig = plt.figure("9, 3") + plt.grid(True) if conf["desLoc"] == 1: xDes = 0 else: xDes = conf["xdots"][-1] * 0.6 props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) plt.text(xDes, conf["yaxismax"]/4, conf["textBox"], fontsize=10, verticalalignment='top', bbox=props) - for i in range(len(conf["data"])): - if conf["type"] == "plot": + if conf["type"] == "plot": + for i in range(len(conf["data"])): plt.plot(conf["xdots"], conf["data"][i], conf["colors"][i], label=conf["labels"][i]) - if conf["type"] == "bar": + elif conf["type"] == "individual_bar": + plt.bar(conf["xdots"], conf["data"]) + elif conf["type"] == "grouped_bar": + for i in range(len(conf["data"])): plt.bar(conf["xdots"], conf["data"][i], label=conf["labels"][i]) plt.title(conf["title"]) plt.ylabel(conf["ylabel"]) @@ -66,6 +70,9 @@ class Visualizor: for result in self.results: plotPath = "results/"+self.execID+"/plots/"+str(result.shape) os.makedirs(plotPath, exist_ok=True) + self.plotMessagesSent(result, plotPath) + self.plotMessagesRecv(result, plotPath) + self.plotSampleRecv(result, plotPath) self.plotMissingSamples(result, plotPath) self.plotProgress(result, plotPath) self.plotSentData(result, plotPath) @@ -74,6 +81,28 @@ class Visualizor: if self.config.saveRCdist: self.plotRowCol(result, plotPath) + def plotSampleRecv(self, result, plotPath): + """Plots the percentage sampleRecv for each node""" + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ + +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns" + conf["title"] = "Percentage of Samples Received by Nodes" + conf["type"] = "individual_bar" + conf["legLoc"] = 1 + conf["desLoc"] = 1 + conf["xlabel"] = "Nodes" + conf["ylabel"] = "Percentage of samples received (%)" + total_samples = result.shape.blockSize * result.shape.blockSize + percentage_data = [(count / total_samples) * 100 for count in result.sampleRecvCount] + conf["data"] = percentage_data + conf["xdots"] = range(result.shape.numberNodes) + conf["path"] = plotPath + "/sampleRecv.png" + maxi = max(conf["data"]) + conf["yaxismax"] = maxi + plotData(conf) + print("Plot %s created." % conf["path"]) + def plotMissingSamples(self, result, plotPath): """Plots the missing samples in the network""" conf = {} @@ -101,9 +130,9 @@ class Visualizor: def plotProgress(self, result, plotPath): """Plots the percentage of nodes ready in the network""" - vector1 = result.metrics["progress"]["nodes ready"] - vector2 = result.metrics["progress"]["validators ready"] - vector3 = result.metrics["progress"]["samples received"] + vector1 = [x * 100 for x in result.metrics["progress"]["nodes ready"]] + vector2 = [x * 100 for x in result.metrics["progress"]["validators ready"]] + vector3 = [x * 100 for x in result.metrics["progress"]["samples received"]] conf = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ @@ -228,7 +257,7 @@ class Visualizor: conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns" conf["title"] = "Row/Column distribution" - conf["type"] = "bar" + conf["type"] = "grouped_bar" conf["legLoc"] = 2 conf["desLoc"] = 2 conf["colors"] = ["r+", "b+"] @@ -246,3 +275,43 @@ class Visualizor: plotData(conf) print("Plot %s created." % conf["path"]) + def plotMessagesSent(self, result, plotPath): + """Plots the number of messages sent by all nodes""" + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ + +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns" + conf["title"] = "Number of Messages Sent by Nodes" + conf["type"] = "individual_bar" + conf["legLoc"] = 1 + conf["desLoc"] = 1 + conf["xlabel"] = "Nodes" + conf["ylabel"] = "Number of Messages Sent" + conf["data"] = result.msgSentCount + conf["xdots"] = range(result.shape.numberNodes) + conf["path"] = plotPath + "/messagesSent.png" + maxi = max(conf["data"]) + conf["yaxismax"] = maxi + plotData(conf) + print("Plot %s created." % conf["path"]) + + def plotMessagesRecv(self, result, plotPath): + """Plots the number of messages received by all nodes""" + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ + +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns" + conf["title"] = "Number of Messages Received by Nodes" + conf["type"] = "individual_bar" + conf["legLoc"] = 1 + conf["desLoc"] = 1 + conf["xlabel"] = "Nodes" + conf["ylabel"] = "Number of Messages Received" + conf["data"] = result.msgRecvCount + conf["xdots"] = range(result.shape.numberNodes) + conf["path"] = plotPath + "/messagesRecv.png" + maxi = max(conf["data"]) + conf["yaxismax"] = maxi + plotData(conf) + print("Plot %s created." % conf["path"]) + diff --git a/smallConf.py b/smallConf.py index 7ab3f44..e1c9125 100644 --- a/smallConf.py +++ b/smallConf.py @@ -45,19 +45,22 @@ numJobs = -1 evenLineDistribution = True # Number of simulation runs with the same parameters for statistical relevance -runs = range(3) +runs = [1] # Number of validators -numberNodes = range(128, 513, 128) +numberNodes = [1024] # select failure model between: "random, sequential, MEP, MEP+1, DEP, DEP+1, MREP, MREP-1" failureModels = ["random"] # Percentage of block not released by producer -failureRates = range(40, 81, 20) +failureRates = [0] + +# Percentage of nodes that are considered malicious +maliciousNodes = [95] # Block size in one dimension in segments. Block is blockSizes * blockSizes segments. -blockSizes = range(64, 113, 128) +blockSizes = [128] # Per-topic mesh neighborhood size netDegrees = range(8, 9, 2) @@ -69,8 +72,8 @@ chis = range(2, 3, 2) class1ratios = [0.8] # Number of validators per beacon node -validatorsPerNode1 = [1] -validatorsPerNode2 = [500] +validatorsPerNode1 = [10] +validatorsPerNode2 = [250] # Set uplink bandwidth in megabits/second bwUplinksProd = [200] @@ -102,9 +105,9 @@ diagnostics = False saveGit = False def nextShape(): - for run, fm, fr, class1ratio, chi, vpn1, vpn2, blockSize, nn, netDegree, bwUplinkProd, bwUplink1, bwUplink2 in itertools.product( - runs, failureModels, failureRates, class1ratios, chis, validatorsPerNode1, validatorsPerNode2, blockSizes, numberNodes, netDegrees, bwUplinksProd, bwUplinks1, bwUplinks2): + for run, fm, fr, mn, class1ratio, chi, vpn1, vpn2, blockSize, nn, netDegree, bwUplinkProd, bwUplink1, bwUplink2 in itertools.product( + runs, failureModels, failureRates, maliciousNodes, class1ratios, chis, validatorsPerNode1, validatorsPerNode2, blockSizes, numberNodes, netDegrees, bwUplinksProd, bwUplinks1, bwUplinks2): # Network Degree has to be an even number if netDegree % 2 == 0: - shape = Shape(blockSize, nn, fm, fr, class1ratio, chi, vpn1, vpn2, netDegree, bwUplinkProd, bwUplink1, bwUplink2, run) + shape = Shape(blockSize, nn, fm, fr, mn, class1ratio, chi, vpn1, vpn2, netDegree, bwUplinkProd, bwUplink1, bwUplink2, run) yield shape From f2a51eb8e1dfd5b49146ba02fb2004a101f154d7 Mon Sep 17 00:00:00 2001 From: Arunima Chaudhuri Date: Tue, 23 Jan 2024 01:46:18 +0530 Subject: [PATCH 02/21] Introduce randomization for malicious nodes Signed-off-by: Arunima Chaudhuri --- DAS/simulator.py | 21 +++++++++++++++++---- DAS/visualizor.py | 20 ++++++++++---------- smallConf.py | 4 ++++ 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/DAS/simulator.py b/DAS/simulator.py index faffdff..00ba951 100644 --- a/DAS/simulator.py +++ b/DAS/simulator.py @@ -71,13 +71,26 @@ class Simulator: assignedRows = [] assignedCols = [] maliciousNodesCount = int((self.shape.maliciousNodes / 100) * self.shape.numberNodes) + remainingMaliciousNodes = maliciousNodesCount + for i in range(self.shape.numberNodes): - if i==0: + if i == 0: amImalicious_value = 0 - elif i < maliciousNodesCount+1: - amImalicious_value = 1 else: - amImalicious_value = 0 + if not self.config.randomizeMaliciousNodes: + # Assign based on predefined pattern when randomization is turned off + if i < maliciousNodesCount + 1: + amImalicious_value = 1 + else: + amImalicious_value = 0 + else: + # Randomly assign amImalicious_value when randomization is turned on + if remainingMaliciousNodes > 0 and random.random() < (self.shape.maliciousNodes / 100): + amImalicious_value = 1 + remainingMaliciousNodes -= 1 + else: + amImalicious_value = 0 + if self.config.evenLineDistribution: if i < int(lightVal/self.shape.vpn1): # First start with the light nodes start = i *self.shape.chi*self.shape.vpn1 diff --git a/DAS/visualizor.py b/DAS/visualizor.py index fb582e9..ab1e57f 100644 --- a/DAS/visualizor.py +++ b/DAS/visualizor.py @@ -12,7 +12,7 @@ def plotData(conf): else: xDes = conf["xdots"][-1] * 0.6 props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) - plt.text(xDes, conf["yaxismax"]/4, conf["textBox"], fontsize=10, verticalalignment='top', bbox=props) + plt.text(xDes, conf["yaxismax"]/3, conf["textBox"], fontsize=10, verticalalignment='top', bbox=props) if conf["type"] == "plot": for i in range(len(conf["data"])): plt.plot(conf["xdots"], conf["data"][i], conf["colors"][i], label=conf["labels"][i]) @@ -86,7 +86,7 @@ class Visualizor: conf = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns" + +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" conf["title"] = "Percentage of Samples Received by Nodes" conf["type"] = "individual_bar" conf["legLoc"] = 1 @@ -108,7 +108,7 @@ class Visualizor: conf = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns" + +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" conf["title"] = "Missing Samples" conf["type"] = "plot" conf["legLoc"] = 1 @@ -136,7 +136,7 @@ class Visualizor: conf = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns" + +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" conf["title"] = "Nodes/validators ready" conf["type"] = "plot" conf["legLoc"] = 2 @@ -168,7 +168,7 @@ class Visualizor: conf = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns" + +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" conf["title"] = "Sent data" conf["type"] = "plot" conf["legLoc"] = 2 @@ -198,7 +198,7 @@ class Visualizor: conf = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns" + +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" conf["title"] = "Received data" conf["type"] = "plot" conf["legLoc"] = 2 @@ -228,7 +228,7 @@ class Visualizor: conf = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns" + +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" conf["title"] = "Duplicated data" conf["type"] = "plot" conf["legLoc"] = 2 @@ -255,7 +255,7 @@ class Visualizor: conf = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns" + +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" conf["title"] = "Row/Column distribution" conf["type"] = "grouped_bar" conf["legLoc"] = 2 @@ -280,7 +280,7 @@ class Visualizor: conf = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns" + +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" conf["title"] = "Number of Messages Sent by Nodes" conf["type"] = "individual_bar" conf["legLoc"] = 1 @@ -300,7 +300,7 @@ class Visualizor: conf = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns" + +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" conf["title"] = "Number of Messages Received by Nodes" conf["type"] = "individual_bar" conf["legLoc"] = 1 diff --git a/smallConf.py b/smallConf.py index e1c9125..e5f6ccd 100644 --- a/smallConf.py +++ b/smallConf.py @@ -59,6 +59,10 @@ failureRates = [0] # Percentage of nodes that are considered malicious maliciousNodes = [95] +# Parameter to determine whether to randomly assign malicious nodes or not +# If True, the malicious nodes will be assigned randomly; if False, a predefined pattern may be used +randomizeMaliciousNodes = True + # Block size in one dimension in segments. Block is blockSizes * blockSizes segments. blockSizes = [128] From 2fc4a963fbedd8b930a7d797cfb7b24d246bf88b Mon Sep 17 00:00:00 2001 From: Arunima Chaudhuri Date: Mon, 29 Jan 2024 19:50:01 +0530 Subject: [PATCH 03/21] add graphs for number of rows and columns repaired Signed-off-by: Arunima Chaudhuri --- DAS/results.py | 4 ++++ DAS/validator.py | 26 ++++++++++++++++---------- DAS/visualizor.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 10 deletions(-) diff --git a/DAS/results.py b/DAS/results.py index 628e8a8..6fbf3a4 100644 --- a/DAS/results.py +++ b/DAS/results.py @@ -20,6 +20,8 @@ class Result: self.msgSentCount = [0] * shape.numberNodes self.msgRecvCount = [0] * shape.numberNodes self.sampleRecvCount = [0] * shape.numberNodes + self.restoreRowCount = [0] * shape.numberNodes + self.restoreColumnCount = [0] * shape.numberNodes def copyValidators(self, validators): """Copy information from simulator.validators to result.""" @@ -28,6 +30,8 @@ class Result: self.msgSentCount[i] = validators[i].msgSentCount self.msgRecvCount[i] = validators[i].msgRecvCount self.sampleRecvCount[i] = validators[i].sampleRecvCount + self.restoreRowCount[i] = validators[i].restoreRowCount + self.restoreColumnCount[i] = validators[i].restoreColumnCount def populate(self, shape, config, missingVector): """It populates part of the result data inside a vector.""" diff --git a/DAS/validator.py b/DAS/validator.py index eaf7686..f2d8e93 100644 --- a/DAS/validator.py +++ b/DAS/validator.py @@ -60,6 +60,8 @@ class Validator: self.msgRecvCount = 0 self.sampleSentCount = 0 self.sampleRecvCount = 0 + self.restoreRowCount = 0 + self.restoreColumnCount = 0 self.logger = logger if self.shape.chi < 1: self.logger.error("Chi has to be greater than 0", extra=self.format) @@ -268,21 +270,23 @@ class Validator: def checkSegmentToNeigh(self, rID, cID, neigh): """Check if a segment should be sent to a neighbor.""" - if (neigh.sent | neigh.received).count(1) >= self.sendLineUntil: - return False # sent enough, other side can restore - i = rID if neigh.dim else cID - if not neigh.sent[i] and not neigh.received[i] : - return True + if not self.amImalicious: + if (neigh.sent | neigh.received).count(1) >= self.sendLineUntil: + return False # sent enough, other side can restore + i = rID if neigh.dim else cID + if not neigh.sent[i] and not neigh.received[i] : + return True else: return False # received or already sent def sendSegmentToNeigh(self, rID, cID, neigh): """Send segment to a neighbor (without checks).""" - self.logger.trace("sending %d/%d to %d", rID, cID, neigh.node.ID, extra=self.format) - i = rID if neigh.dim else cID - neigh.sent[i] = 1 - neigh.node.receiveSegment(rID, cID, self.ID) - self.statsTxInSlot += 1 + if not self.amImalicious: + self.logger.trace("sending %d/%d to %d", rID, cID, neigh.node.ID, extra=self.format) + i = rID if neigh.dim else cID + neigh.sent[i] = 1 + neigh.node.receiveSegment(rID, cID, self.ID) + self.statsTxInSlot += 1 def checkSendSegmentToNeigh(self, rID, cID, neigh): """Check and send a segment to a neighbor if needed.""" @@ -516,6 +520,7 @@ class Validator: if (rep.any()): # If operation is based on send queues, segments should # be queued after successful repair. + self.restoreRowCount += 1 for i in range(len(rep)): if rep[i]: self.logger.trace("Rep: %d,%d", id, i, extra=self.format) @@ -535,6 +540,7 @@ class Validator: if (rep.any()): # If operation is based on send queues, segments should # be queued after successful repair. + self.restoreColumnCount += 1 for i in range(len(rep)): if rep[i]: self.logger.trace("Rep: %d,%d", i, id, extra=self.format) diff --git a/DAS/visualizor.py b/DAS/visualizor.py index ab1e57f..50ed89f 100644 --- a/DAS/visualizor.py +++ b/DAS/visualizor.py @@ -70,6 +70,8 @@ class Visualizor: for result in self.results: plotPath = "results/"+self.execID+"/plots/"+str(result.shape) os.makedirs(plotPath, exist_ok=True) + self.plotRestoreRowCount(result, plotPath) + self.plotRestoreColumnCount(result, plotPath) self.plotMessagesSent(result, plotPath) self.plotMessagesRecv(result, plotPath) self.plotSampleRecv(result, plotPath) @@ -81,6 +83,46 @@ class Visualizor: if self.config.saveRCdist: self.plotRowCol(result, plotPath) + def plotRestoreRowCount(self, result, plotPath): + """Plots the restoreRowCount for each node""" + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ + +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" + conf["title"] = "Restore Row Count for Each Node" + conf["type"] = "individual_bar" + conf["legLoc"] = 1 + conf["desLoc"] = 1 + conf["xlabel"] = "Nodes" + conf["ylabel"] = "Restore Row Count" + conf["data"] = result.restoreRowCount + conf["xdots"] = range(result.shape.numberNodes) + conf["path"] = plotPath + "/restoreRowCount.png" + maxi = max(conf["data"]) + conf["yaxismax"] = maxi + plotData(conf) + print("Plot %s created." % conf["path"]) + + def plotRestoreColumnCount(self, result, plotPath): + """Plots the restoreColumnCount for each node""" + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ + +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" + conf["title"] = "Restore Column Count for Each Node" + conf["type"] = "individual_bar" + conf["legLoc"] = 1 + conf["desLoc"] = 1 + conf["xlabel"] = "Nodes" + conf["ylabel"] = "Restore Column Count" + conf["data"] = result.restoreColumnCount + conf["xdots"] = range(result.shape.numberNodes) + conf["path"] = plotPath + "/restoreColumnCount.png" + maxi = max(conf["data"]) + conf["yaxismax"] = maxi + plotData(conf) + print("Plot %s created." % conf["path"]) + def plotSampleRecv(self, result, plotPath): """Plots the percentage sampleRecv for each node""" conf = {} From 7ed3d8c690f411b8dcf21ebdefc63abc9757ff30 Mon Sep 17 00:00:00 2001 From: Arunima Chaudhuri Date: Fri, 2 Feb 2024 23:27:38 +0530 Subject: [PATCH 04/21] Debugged to ensure accurate results Signed-off-by: Arunima Chaudhuri --- DAS/simulator.py | 17 ++++++++++-- DAS/validator.py | 67 +++++++++++++++++++++++++----------------------- 2 files changed, 50 insertions(+), 34 deletions(-) diff --git a/DAS/simulator.py b/DAS/simulator.py index 00ba951..d1b6abe 100644 --- a/DAS/simulator.py +++ b/DAS/simulator.py @@ -241,7 +241,8 @@ class Simulator: self.glob.checkRowsColumns(self.validators) for i in range(0,self.shape.numberNodes): if i == self.proposerID: - self.validators[i].initBlock() + # self.validators[i].initBlock() + self.logger.warning("I am a block proposer.", extra=self.format) else: self.validators[i].logIDs() arrived, expected, ready, validatedall, validated = self.glob.checkStatus(self.validators) @@ -256,7 +257,8 @@ class Simulator: oldMissingSamples = missingSamples self.logger.debug("PHASE SEND %d" % steps, extra=self.format) for i in range(0,self.shape.numberNodes): - self.validators[i].send() + if not self.validators[i].amImalicious: + self.validators[i].send() self.logger.debug("PHASE RECEIVE %d" % steps, extra=self.format) for i in range(1,self.shape.numberNodes): self.validators[i].receiveRowsColumns() @@ -323,6 +325,17 @@ class Simulator: if not self.validators[i].amIaddedToQueue : malicious_nodes_not_added_count += 1 + for i in range(0,self.shape.numberNodes): + column_ids = [] + row_ids = [] + for rID in self.validators[i].rowIDs: + row_ids.append(rID) + for cID in self.validators[i].columnIDs: + column_ids.append(cID) + + self.logger.debug("List of columnIDs for %d node: %s", i, column_ids, extra=self.format) + self.logger.debug("List of rowIDs for %d node: %s", i, row_ids, extra=self.format) + self.logger.debug("Number of malicious nodes not added to the send queue: %d" % malicious_nodes_not_added_count, extra=self.format) malicious_nodes_not_added_percentage = (malicious_nodes_not_added_count * 100)/(self.shape.numberNodes) self.logger.debug("Percentage of malicious nodes not added to the send queue: %d" % malicious_nodes_not_added_percentage, extra=self.format) diff --git a/DAS/validator.py b/DAS/validator.py index f2d8e93..86e2107 100644 --- a/DAS/validator.py +++ b/DAS/validator.py @@ -305,7 +305,7 @@ class Validator: while self.sendQueue: (rID, cID) = self.sendQueue[0] - if rID in self.rowIDs: + if rID in self.rowIDs and not self.amImalicious: for _, neigh in shuffledDict(self.rowNeighbors[rID], self.shuffleNeighbors): if not self.amImalicious: self.checkSendSegmentToNeigh(rID, cID, neigh) @@ -313,7 +313,7 @@ class Validator: if self.statsTxInSlot >= self.bwUplink: return - if cID in self.columnIDs: + if cID in self.columnIDs and not self.amImalicious: for _, neigh in shuffledDict(self.columnNeighbors[cID], self.shuffleNeighbors): if not self.amImalicious: self.checkSendSegmentToNeigh(rID, cID, neigh) @@ -370,31 +370,32 @@ class Validator: def collectSegmentsToSend(): # yields list of segments to send as (dim, lineID, id) segmentsToSend = [] - for rID, neighs in self.rowNeighbors.items(): - line = self.getRow(rID) - needed = zeros(self.shape.blockSize) - for neigh in neighs.values(): - sentOrReceived = neigh.received | neigh.sent - if sentOrReceived.count(1) < self.sendLineUntil: - needed |= ~sentOrReceived - needed &= line - if (needed).any(): - for i in range(len(needed)): - if needed[i]: - segmentsToSend.append((0, rID, i)) + if not self.amImalicious: + for rID, neighs in self.rowNeighbors.items(): + line = self.getRow(rID) + needed = zeros(self.shape.blockSize) + for neigh in neighs.values(): + sentOrReceived = neigh.received | neigh.sent + if sentOrReceived.count(1) < self.sendLineUntil: + needed |= ~sentOrReceived + needed &= line + if (needed).any(): + for i in range(len(needed)): + if needed[i]: + segmentsToSend.append((0, rID, i)) - for cID, neighs in self.columnNeighbors.items(): - line = self.getColumn(cID) - needed = zeros(self.shape.blockSize) - for neigh in neighs.values(): - sentOrReceived = neigh.received | neigh.sent - if sentOrReceived.count(1) < self.sendLineUntil: - needed |= ~sentOrReceived - needed &= line - if (needed).any(): - for i in range(len(needed)): - if needed[i]: - segmentsToSend.append((1, cID, i)) + for cID, neighs in self.columnNeighbors.items(): + line = self.getColumn(cID) + needed = zeros(self.shape.blockSize) + for neigh in neighs.values(): + sentOrReceived = neigh.received | neigh.sent + if sentOrReceived.count(1) < self.sendLineUntil: + needed |= ~sentOrReceived + needed &= line + if (needed).any(): + for i in range(len(needed)): + if needed[i]: + segmentsToSend.append((1, cID, i)) return segmentsToSend @@ -405,12 +406,12 @@ class Validator: for dim, lineID, id in self.segmentShuffleGen: if dim == 0: for _, neigh in shuffledDict(self.rowNeighbors[lineID], self.shuffleNeighbors): - if self.checkSegmentToNeigh(lineID, id, neigh): + if self.checkSegmentToNeigh(lineID, id, neigh) and not self.amImalicious: yield((lineID, id, neigh)) break else: for _, neigh in shuffledDict(self.columnNeighbors[lineID], self.shuffleNeighbors): - if self.checkSegmentToNeigh(id, lineID, neigh): + if self.checkSegmentToNeigh(id, lineID, neigh) and not self.amImalicious: yield((id, lineID, neigh)) break @@ -425,7 +426,8 @@ class Validator: for rid, cid, neigh in nextSegment(): # segments are checked just before yield, so we can send directly - self.sendSegmentToNeigh(rid, cid, neigh) + if not self.amImalicious: + self.sendSegmentToNeigh(rid, cid, neigh) if self.statsTxInSlot >= self.bwUplink: if not self.segmentShuffleSchedulerPersist: @@ -450,7 +452,7 @@ class Validator: cID = random.randrange(0, self.shape.blockSize) if self.block.getSegment(rID, cID) : neigh = random.choice(list(self.rowNeighbors[rID].values())) - if self.checkSegmentToNeigh(rID, cID, neigh): + if self.checkSegmentToNeigh(rID, cID, neigh) and not self.amImalicious: yield(rID, cID, neigh) t = tries if self.columnIDs: @@ -458,14 +460,15 @@ class Validator: rID = random.randrange(0, self.shape.blockSize) if self.block.getSegment(rID, cID) : neigh = random.choice(list(self.columnNeighbors[cID].values())) - if self.checkSegmentToNeigh(rID, cID, neigh): + if self.checkSegmentToNeigh(rID, cID, neigh) and not self.amImalicious: yield(rID, cID, neigh) t = tries t -= 1 for rid, cid, neigh in nextSegment(): # segments are checked just before yield, so we can send directly - self.sendSegmentToNeigh(rid, cid, neigh) + if not self.amImalicious: + self.sendSegmentToNeigh(rid, cid, neigh) if self.statsTxInSlot >= self.bwUplink: return From 7875023ef0ff8ada7ff9aee385dffee9fa4e1f2f Mon Sep 17 00:00:00 2001 From: Arunima Chaudhuri Date: Thu, 15 Feb 2024 23:48:30 +0530 Subject: [PATCH 05/21] Independent dimensions Signed-off-by: Arunima Chaudhuri --- .gitignore | 2 +- DAS/block.py | 57 ++++++++++++++++------------- DAS/observer.py | 15 ++++---- DAS/shape.py | 20 +++++++---- DAS/simulator.py | 52 +++++++++++++++------------ DAS/validator.py | 91 +++++++++++++++++++++++------------------------ DAS/visualizer.py | 6 ++-- DAS/visualizor.py | 54 +++++++++++++++------------- smallConf.py | 27 +++++++------- 9 files changed, 176 insertions(+), 148 deletions(-) diff --git a/.gitignore b/.gitignore index 492044a..43965e8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ *.swp *.pyc results/* -myenv +myenv*/ doc/_build !results/plots.py Frontend/ diff --git a/DAS/block.py b/DAS/block.py index f76a944..ef3f4f5 100644 --- a/DAS/block.py +++ b/DAS/block.py @@ -7,10 +7,18 @@ from bitarray.util import zeros class Block: """This class represents a block in the Ethereum blockchain.""" - def __init__(self, blockSize): - """Initialize the block with a data array of blocksize^2 zeros.""" - self.blockSize = blockSize - self.data = zeros(self.blockSize*self.blockSize) + def __init__(self, blockSizeR, blockSizeRK=0, blockSizeC=0, blockSizeCK=0): + """Initialize the block with a data array of blocksize^2 zeros. + BlockSizeR: row size + BlockSizeRK: original row size, before erasure coding to BlocksSizeR + BlockSizeC: column size (i.e. number of rows) + BlockSizeCK: original column size, before erasure coding to BlocksSizeR + """ + self.blockSizeR = blockSizeR + self.blockSizeRK = blockSizeRK if blockSizeRK else blockSizeR/2 + self.blockSizeC = blockSizeC if blockSizeC else blockSizeR + self.blockSizeCK = blockSizeCK if blockSizeCK else blockSizeRK + self.data = zeros(self.blockSizeR*self.blockSizeC) def fill(self): """It fills the block data with ones.""" @@ -22,62 +30,61 @@ class Block: def getSegment(self, rowID, columnID): """Check whether a segment is included""" - return self.data[rowID*self.blockSize + columnID] + return self.data[rowID*self.blockSizeR + columnID] def setSegment(self, rowID, columnID, value = 1): """Set value for a segment (default 1)""" - self.data[rowID*self.blockSize + columnID] = value + self.data[rowID*self.blockSizeR + columnID] = value def getColumn(self, columnID): """It returns the block column corresponding to columnID.""" - return self.data[columnID::self.blockSize] + return self.data[columnID::self.blockSizeR] def mergeColumn(self, columnID, column): """It merges (OR) the existing column with the received one.""" - self.data[columnID::self.blockSize] |= column + self.data[columnID::self.blockSizeR] |= column def repairColumn(self, id): - """It repairs the entire column if it has at least blockSize/2 ones. + """It repairs the entire column if it has at least blockSizeCK ones. Returns: list of repaired segments """ - line = self.data[id::self.blockSize] + line = self.data[id::self.blockSizeR] success = line.count(1) - if success >= self.blockSize/2: + if success >= self.blockSizeCK: ret = ~line - self.data[id::self.blockSize] = 1 + self.data[id::self.blockSizeR] = 1 else: - ret = zeros(self.blockSize) + ret = zeros(self.blockSizeC) return ret def getRow(self, rowID): """It returns the block row corresponding to rowID.""" - return self.data[rowID*self.blockSize:(rowID+1)*self.blockSize] + return self.data[rowID*self.blockSizeR:(rowID+1)*self.blockSizeR] def mergeRow(self, rowID, row): """It merges (OR) the existing row with the received one.""" - self.data[rowID*self.blockSize:(rowID+1)*self.blockSize] |= row + self.data[rowID*self.blockSizeR:(rowID+1)*self.blockSizeR] |= row def repairRow(self, id): - """It repairs the entire row if it has at least blockSize/2 ones. + """It repairs the entire row if it has at least blockSizeRK ones. Returns: list of repaired segments. """ - line = self.data[id*self.blockSize:(id+1)*self.blockSize] + line = self.data[id*self.blockSizeR:(id+1)*self.blockSizeR] success = line.count(1) - if success >= self.blockSize/2: + if success >= self.blockSizeRK: ret = ~line - self.data[id*self.blockSize:(id+1)*self.blockSize] = 1 + self.data[id*self.blockSizeR:(id+1)*self.blockSizeR] = 1 else: - ret = zeros(self.blockSize) + ret = zeros(self.blockSizeR) return ret def print(self): """It prints the block in the terminal (outside of the logger rules)).""" - dash = "-" * (self.blockSize+2) + dash = "-" * (self.blockSizeR+2) print(dash) - for i in range(self.blockSize): + for i in range(self.blockSizeC): line = "|" - for j in range(self.blockSize): - line += "%i" % self.data[(i*self.blockSize)+j] + for j in range(self.blockSizeR): + line += "%i" % self.data[(i*self.blockSizeR)+j] print(line+"|") print(dash) - diff --git a/DAS/observer.py b/DAS/observer.py index beba4ad..328a11d 100644 --- a/DAS/observer.py +++ b/DAS/observer.py @@ -11,10 +11,11 @@ class Observer: self.config = config self.format = {"entity": "Observer"} self.logger = logger - self.block = [0] * self.config.blockSize * self.config.blockSize - self.rows = [0] * self.config.blockSize - self.columns = [0] * self.config.blockSize - self.broadcasted = Block(self.config.blockSize) + self.block = [0] * self.config.blockSizeR * self.config.blockSizeC + self.rows = [0] * self.config.blockSizeC + self.columns = [0] * self.config.blockSizeR + self.broadcasted = Block(self.config.blockSizeR, self.config.blockSizeRK, + self.config.blockSizeC, self.config.blockSizeCK) def checkRowsColumns(self, validators): @@ -26,7 +27,7 @@ class Observer: for c in val.columnIDs: self.columns[c] += 1 - for i in range(self.config.blockSize): + for i in range(self.config.blockSizeC): self.logger.debug("Row/Column %d have %d and %d validators assigned." % (i, self.rows[i], self.columns[i]), extra=self.format) if self.rows[i] == 0 or self.columns[i] == 0: self.logger.warning("There is a row/column that has not been assigned", extra=self.format) @@ -34,7 +35,7 @@ class Observer: def checkBroadcasted(self): """It checks how many broadcasted samples are still missing in the network.""" zeros = 0 - for i in range(self.blockSize * self.blockSize): + for i in range(self.blockSizeR * self.blockSizeC): if self.broadcasted.data[i] == 0: zeros += 1 if zeros > 0: @@ -99,4 +100,4 @@ class Observer: "RxDup": {"mean": meanOrNan(RxDup), "max": maxOrNan(RxDup)}, } - return trafficStats + return trafficStats \ No newline at end of file diff --git a/DAS/shape.py b/DAS/shape.py index 109bf97..c2a1ff7 100644 --- a/DAS/shape.py +++ b/DAS/shape.py @@ -3,17 +3,22 @@ class Shape: """This class represents a set of parameters for a specific simulation.""" - def __init__(self, blockSize, numberNodes, failureModel, failureRate, maliciousNodes, class1ratio, chi, vpn1, vpn2, netDegree, bwUplinkProd, bwUplink1, bwUplink2, run): + def __init__(self, blockSizeR, blockSizeRK, blockSizeC, blockSizeCK, + numberNodes, failureModel, failureRate, maliciousNodes, class1ratio, chiR, chiC, vpn1, vpn2, netDegree, bwUplinkProd, bwUplink1, bwUplink2, run): """Initializes the shape with the parameters passed in argument.""" self.run = run self.numberNodes = numberNodes - self.blockSize = blockSize + self.blockSizeR = blockSizeR + self.blockSizeRK = blockSizeRK + self.blockSizeC = blockSizeC + self.blockSizeCK = blockSizeCK self.failureModel = failureModel self.failureRate = failureRate self.maliciousNodes = maliciousNodes self.netDegree = netDegree self.class1ratio = class1ratio - self.chi = chi + self.chiR = chiR + self.chiC = chiC self.vpn1 = vpn1 self.vpn2 = vpn2 self.bwUplinkProd = bwUplinkProd @@ -24,12 +29,16 @@ class Shape: def __repr__(self): """Returns a printable representation of the shape""" shastr = "" - shastr += "bs-"+str(self.blockSize) + shastr += "-bsrn-"+str(self.blockSizeR) + shastr += "-bsrk-"+str(self.blockSizeRK) + shastr += "-bscn-"+str(self.blockSizeC) + shastr += "-bsck-"+str(self.blockSizeCK) shastr += "-nn-"+str(self.numberNodes) shastr += "-fm-"+str(self.failureModel) shastr += "-fr-"+str(self.failureRate) shastr += "-c1r-"+str(self.class1ratio) - shastr += "-chi-"+str(self.chi) + shastr += "-chir-"+str(self.chiR) + shastr += "-chic-"+str(self.chiC) shastr += "-vpn1-"+str(self.vpn1) shastr += "-vpn2-"+str(self.vpn2) shastr += "-bwupprod-"+str(self.bwUplinkProd) @@ -43,4 +52,3 @@ class Shape: def setSeed(self, seed): """Adds the random seed to the shape""" self.randomSeed = seed - diff --git a/DAS/simulator.py b/DAS/simulator.py index d1b6abe..50b7289 100644 --- a/DAS/simulator.py +++ b/DAS/simulator.py @@ -41,7 +41,7 @@ class Simulator: # pushed out by the proposer. # 1: the data is sent out exactly once on rows and once on columns (2 copies in total) # self.shape.netDegree: default behavior similar (but not same) to previous code - self.proposerPublishTo = self.shape.netDegree + self.proposerPublishTo = self.shape.netDegree # TODO: make this an external parameter def initValidators(self): """It initializes all the validators in the network.""" @@ -54,17 +54,20 @@ class Simulator: lightVal = lightNodes * self.shape.vpn1 heavyVal = heavyNodes * self.shape.vpn2 totalValidators = lightVal + heavyVal - totalRows = totalValidators * self.shape.chi - rows = list(range(self.shape.blockSize)) * (int(totalRows/self.shape.blockSize)+1) - columns = list(range(self.shape.blockSize)) * (int(totalRows/self.shape.blockSize)+1) + totalRows = totalValidators * self.shape.chiR + totalColumns = totalValidators * self.shape.chiC + rows = list(range(self.shape.blockSizeC)) * (int(totalRows/self.shape.blockSizeC)+1) + columns = list(range(self.shape.blockSizeR)) * (int(totalColumns/self.shape.blockSizeR)+1) rows = rows[0:totalRows] columns = columns[0:totalRows] random.shuffle(rows) random.shuffle(columns) - offset = lightVal*self.shape.chi + offsetR = lightVal*self.shape.chiR + offsetC = lightVal*self.shape.chiC self.logger.debug("There is a total of %d nodes, %d light and %d heavy." % (self.shape.numberNodes, lightNodes, heavyNodes), extra=self.format) self.logger.debug("There is a total of %d validators, %d in light nodes and %d in heavy nodes" % (totalValidators, lightVal, heavyVal), extra=self.format) - self.logger.debug("Shuffling a total of %d rows/columns to be assigned (X=%d)" % (len(rows), self.shape.chi), extra=self.format) + self.logger.debug("Shuffling a total of %d rows to be assigned (X=%d)" % (len(rows), self.shape.chiR), extra=self.format) + self.logger.debug("Shuffling a total of %d columns to be assigned (X=%d)" % (len(columns), self.shape.chiC), extra=self.format) self.logger.debug("Shuffled rows: %s" % str(rows), extra=self.format) self.logger.debug("Shuffled columns: %s" % str(columns), extra=self.format) @@ -93,14 +96,18 @@ class Simulator: if self.config.evenLineDistribution: if i < int(lightVal/self.shape.vpn1): # First start with the light nodes - start = i *self.shape.chi*self.shape.vpn1 - end = (i+1)*self.shape.chi*self.shape.vpn1 + startR = i *self.shape.chiR*self.shape.vpn1 + endR = (i+1)*self.shape.chiR*self.shape.vpn1 + startC = i *self.shape.chiC*self.shape.vpn1 + endC = (i+1)*self.shape.chiC*self.shape.vpn1 else: j = i - int(lightVal/self.shape.vpn1) - start = offset+( j *self.shape.chi*self.shape.vpn2) - end = offset+((j+1)*self.shape.chi*self.shape.vpn2) - r = rows[start:end] - c = columns[start:end] + startR = offsetR+( j *self.shape.chiR*self.shape.vpn2) + endR = offsetR+((j+1)*self.shape.chiR*self.shape.vpn2) + startC = offsetC+( j *self.shape.chiC*self.shape.vpn2) + endC = offsetC+((j+1)*self.shape.chiC*self.shape.vpn2) + r = rows[startR:endR] + c = columns[startC:endC] val = Validator(i, int(not i!=0), amImalicious_value, self.logger, self.shape, self.config, r, c) self.logger.debug("Node %d has row IDs: %s" % (val.ID, val.rowIDs), extra=self.format) self.logger.debug("Node %d has column IDs: %s" % (val.ID, val.columnIDs), extra=self.format) @@ -125,8 +132,8 @@ class Simulator: def initNetwork(self): """It initializes the simulated network.""" - rowChannels = [[] for i in range(self.shape.blockSize)] - columnChannels = [[] for i in range(self.shape.blockSize)] + rowChannels = [[] for i in range(self.shape.blockSizeC)] + columnChannels = [[] for i in range(self.shape.blockSizeR)] for v in self.validators: if not (self.proposerPublishOnly and v.amIproposer): for id in v.rowIDs: @@ -142,7 +149,7 @@ class Simulator: self.logger.debug("Number of validators per row; Min: %d, Max: %d" % (min(self.distR), max(self.distR)), extra=self.format) self.logger.debug("Number of validators per column; Min: %d, Max: %d" % (min(self.distC), max(self.distC)), extra=self.format) - for id in range(self.shape.blockSize): + for id in range(self.shape.blockSizeC): # If the number of nodes in a channel is smaller or equal to the # requested degree, a fully connected graph is used. For n>d, a random @@ -160,9 +167,11 @@ class Simulator: for u, v in G.edges: val1=rowChannels[id][u] val2=rowChannels[id][v] - val1.rowNeighbors[id].update({val2.ID : Neighbor(val2, 0, self.shape.blockSize)}) - val2.rowNeighbors[id].update({val1.ID : Neighbor(val1, 0, self.shape.blockSize)}) + val1.rowNeighbors[id].update({val2.ID : Neighbor(val2, 0, self.shape.blockSizeR)}) + val2.rowNeighbors[id].update({val1.ID : Neighbor(val1, 0, self.shape.blockSizeR)}) + for id in range(self.shape.blockSizeR): + if not columnChannels[id]: self.logger.error("No nodes for column %d !" % id, extra=self.format) continue @@ -176,8 +185,8 @@ class Simulator: for u, v in G.edges: val1=columnChannels[id][u] val2=columnChannels[id][v] - val1.columnNeighbors[id].update({val2.ID : Neighbor(val2, 1, self.shape.blockSize)}) - val2.columnNeighbors[id].update({val1.ID : Neighbor(val1, 1, self.shape.blockSize)}) + val1.columnNeighbors[id].update({val2.ID : Neighbor(val2, 1, self.shape.blockSizeC)}) + val2.columnNeighbors[id].update({val1.ID : Neighbor(val1, 1, self.shape.blockSizeC)}) for v in self.validators: if (self.proposerPublishOnly and v.amIproposer): @@ -185,12 +194,12 @@ class Simulator: count = min(self.proposerPublishTo, len(rowChannels[id])) publishTo = random.sample(rowChannels[id], count) for vi in publishTo: - v.rowNeighbors[id].update({vi.ID : Neighbor(vi, 0, self.shape.blockSize)}) + v.rowNeighbors[id].update({vi.ID : Neighbor(vi, 0, self.shape.blockSizeR)}) for id in v.columnIDs: count = min(self.proposerPublishTo, len(columnChannels[id])) publishTo = random.sample(columnChannels[id], count) for vi in publishTo: - v.columnNeighbors[id].update({vi.ID : Neighbor(vi, 1, self.shape.blockSize)}) + v.columnNeighbors[id].update({vi.ID : Neighbor(vi, 1, self.shape.blockSizeC)}) if self.logger.isEnabledFor(logging.DEBUG): for i in range(0, self.shape.numberNodes): @@ -349,4 +358,3 @@ class Simulator: self.result.populate(self.shape, self.config, missingVector) self.result.copyValidators(self.validators) return self.result - diff --git a/DAS/validator.py b/DAS/validator.py index 86e2107..ae99d6f 100644 --- a/DAS/validator.py +++ b/DAS/validator.py @@ -42,15 +42,15 @@ class Validator: """It initializes the validator with the logger shape and rows/columns. If rows/columns are specified these are observed, otherwise (default) - chi rows and columns are selected randomly. + chiR rows and chiC columns are selected randomly. """ self.shape = shape FORMAT = "%(levelname)s : %(entity)s : %(message)s" self.ID = ID self.format = {"entity": "Val "+str(self.ID)} - self.block = Block(self.shape.blockSize) - self.receivedBlock = Block(self.shape.blockSize) + self.block = Block(self.shape.blockSizeR, self.shape.blockSizeRK, self.shape.blockSizeC, self.shape.blockSizeCK) + self.receivedBlock = Block(self.shape.blockSizeR, self.shape.blockSizeRK, self.shape.blockSizeC, self.shape.blockSizeCK) self.receivedQueue = deque() self.sendQueue = deque() self.amIproposer = amIproposer @@ -63,15 +63,17 @@ class Validator: self.restoreRowCount = 0 self.restoreColumnCount = 0 self.logger = logger - if self.shape.chi < 1: + if self.shape.chiR < 1 and self.shape.chiC < 1: self.logger.error("Chi has to be greater than 0", extra=self.format) - elif self.shape.chi > self.shape.blockSize: - self.logger.error("Chi has to be smaller than %d" % self.shape.blockSize, extra=self.format) + elif self.shape.chiC > self.shape.blockSizeR: + self.logger.error("ChiC has to be smaller than %d" % self.shape.blockSizeR, extra=self.format) + elif self.shape.chiR > self.shape.blockSizeC: + self.logger.error("ChiR has to be smaller than %d" % self.shape.blockSizeC, extra=self.format) else: if amIproposer: self.nodeClass = 0 - self.rowIDs = range(shape.blockSize) - self.columnIDs = range(shape.blockSize) + self.rowIDs = range(shape.blockSizeC) + self.columnIDs = range(shape.blockSizeR) else: #if shape.deterministic: # random.seed(self.ID) @@ -80,8 +82,8 @@ class Validator: self.vRowIDs = [] self.vColumnIDs = [] for i in range(self.vpn): - self.vRowIDs.append(set(rows[i*self.shape.chi:(i+1)*self.shape.chi]) if rows else set(random.sample(range(self.shape.blockSize), self.shape.chi))) - self.vColumnIDs.append(set(columns[i*self.shape.chi:(i+1)*self.shape.chi]) if columns else set(random.sample(range(self.shape.blockSize), self.shape.chi))) + self.vRowIDs.append(set(rows[i*self.shape.chiR:(i+1)*self.shape.chiR]) if rows else set(random.sample(range(self.shape.blockSizeC), self.shape.chiR))) + self.vColumnIDs.append(set(columns[i*self.shape.chiC:(i+1)*self.shape.chiC]) if columns else set(random.sample(range(self.shape.blockSizeR), self.shape.chiC))) self.rowIDs = set.union(*self.vRowIDs) self.columnIDs = set.union(*self.vColumnIDs) self.rowNeighbors = collections.defaultdict(dict) @@ -107,7 +109,8 @@ class Validator: self.bwUplink *= 1e3 / 8 * config.stepDuration / config.segmentSize self.repairOnTheFly = True - self.sendLineUntil = (self.shape.blockSize + 1) // 2 # stop sending on a p2p link if at least this amount of samples passed + self.sendLineUntilR = self.shape.blockSizeRK # stop sending on a p2p link if at least this amount of samples passed + self.sendLineUntilC = self.shape.blockSizeCK # stop sending on a p2p link if at least this amount of samples passed self.perNeighborQueue = True # queue incoming messages to outgoing connections on arrival (as typical GossipSub impl) self.shuffleQueues = True # shuffle the order of picking from active queues of a sender node self.perNodeQueue = False # keep a global queue of incoming messages for later sequential dispatch @@ -132,57 +135,53 @@ class Validator: else: self.logger.debug("Creating block...", extra=self.format) if self.shape.failureModel == "random": - order = [i for i in range(self.shape.blockSize * self.shape.blockSize)] + order = [i for i in range(self.shape.blockSizeR * self.shape.blockSizeC)] order = random.sample(order, int((1 - self.shape.failureRate/100) * len(order))) for i in order: self.block.data[i] = 1 elif self.shape.failureModel == "sequential": - order = [i for i in range(self.shape.blockSize * self.shape.blockSize)] + order = [i for i in range(self.shape.blockSizeR * self.shape.blockSizeC)] order = order[:int((1 - self.shape.failureRate/100) * len(order))] for i in order: self.block.data[i] = 1 elif self.shape.failureModel == "MEP": # Minimal size non-recoverable Erasure Pattern - for r in range(self.shape.blockSize): - for c in range(self.shape.blockSize): - k = self.shape.blockSize/2 - if r > k or c > k: + for r in range(self.shape.blockSizeR): + for c in range(self.shape.blockSizeC): + if r > self.shape.blockSizeRK or c > self.shape.blockSizeCK: self.block.setSegment(r,c) elif self.shape.failureModel == "MEP+1": # MEP +1 segment to make it recoverable - for r in range(self.shape.blockSize): - for c in range(self.shape.blockSize): - k = self.shape.blockSize/2 - if r > k or c > k: + for r in range(self.shape.blockSizeR): + for c in range(self.shape.blockSizeC): + if r > self.shape.blockSizeRK or c > self.shape.blockSizeCK: self.block.setSegment(r,c) self.block.setSegment(0, 0) elif self.shape.failureModel == "DEP": - for r in range(self.shape.blockSize): - for c in range(self.shape.blockSize): - k = self.shape.blockSize/2 - if (r+c) % self.shape.blockSize > k: + assert(self.shape.blockSizeR == self.shape.blockSizeC and self.shape.blockSizeRK == self.shape.blockSizeCK) + for r in range(self.shape.blockSizeR): + for c in range(self.shape.blockSizeC): + if (r+c) % self.shape.blockSizeR > self.shape.blockSizeRK: self.block.setSegment(r,c) elif self.shape.failureModel == "DEP+1": - for r in range(self.shape.blockSize): - for c in range(self.shape.blockSize): - k = self.shape.blockSize/2 - if (r+c) % self.shape.blockSize > k: + assert(self.shape.blockSizeR == self.shape.blockSizeC and self.shape.blockSizeRK == self.shape.blockSizeCK) + for r in range(self.shape.blockSizeR): + for c in range(self.shape.blockSizeC): + if (r+c) % self.shape.blockSizeR > self.shape.blockSizeRK: self.block.setSegment(r,c) self.block.setSegment(0, 0) elif self.shape.failureModel == "MREP": # Minimum size Recoverable Erasure Pattern - for r in range(self.shape.blockSize): - for c in range(self.shape.blockSize): - k = self.shape.blockSize/2 - if r < k and c < k: + for r in range(self.shape.blockSizeR): + for c in range(self.shape.blockSizeC): + if r < self.shape.blockSizeRK or c < self.shape.blockSizeCK: self.block.setSegment(r,c) elif self.shape.failureModel == "MREP-1": # make MREP non-recoverable - for r in range(self.shape.blockSize): - for c in range(self.shape.blockSize): - k = self.shape.blockSize/2 - if r < k and c < k: + for r in range(self.shape.blockSizeR): + for c in range(self.shape.blockSizeC): + if r < self.shape.blockSizeRK or c < self.shape.blockSizeCK: self.block.setSegment(r,c) self.block.setSegment(0, 0, 0) nbFailures = self.block.data.count(0) - measuredFailureRate = nbFailures * 100 / (self.shape.blockSize * self.shape.blockSize) + measuredFailureRate = nbFailures * 100 / (self.shape.blockSizeR * self.shape.blockSizeC) self.logger.debug("Number of failures: %d (%0.02f %%)", nbFailures, measuredFailureRate, extra=self.format) def getColumn(self, index): @@ -271,7 +270,7 @@ class Validator: def checkSegmentToNeigh(self, rID, cID, neigh): """Check if a segment should be sent to a neighbor.""" if not self.amImalicious: - if (neigh.sent | neigh.received).count(1) >= self.sendLineUntil: + if (neigh.sent | neigh.received).count(1) >= (self.sendLineUntilC if neigh.dim else self.sendLineUntilR): return False # sent enough, other side can restore i = rID if neigh.dim else cID if not neigh.sent[i] and not neigh.received[i] : @@ -373,10 +372,10 @@ class Validator: if not self.amImalicious: for rID, neighs in self.rowNeighbors.items(): line = self.getRow(rID) - needed = zeros(self.shape.blockSize) + needed = zeros(self.shape.blockSizeR) for neigh in neighs.values(): sentOrReceived = neigh.received | neigh.sent - if sentOrReceived.count(1) < self.sendLineUntil: + if sentOrReceived.count(1) < self.sendLineUntilR: needed |= ~sentOrReceived needed &= line if (needed).any(): @@ -386,10 +385,10 @@ class Validator: for cID, neighs in self.columnNeighbors.items(): line = self.getColumn(cID) - needed = zeros(self.shape.blockSize) + needed = zeros(self.shape.blockSizeC) for neigh in neighs.values(): sentOrReceived = neigh.received | neigh.sent - if sentOrReceived.count(1) < self.sendLineUntil: + if sentOrReceived.count(1) < self.sendLineUntilC: needed |= ~sentOrReceived needed &= line if (needed).any(): @@ -449,7 +448,7 @@ class Validator: while t: if self.rowIDs: rID = random.choice(self.rowIDs) - cID = random.randrange(0, self.shape.blockSize) + cID = random.randrange(0, self.shape.blockSizeR) if self.block.getSegment(rID, cID) : neigh = random.choice(list(self.rowNeighbors[rID].values())) if self.checkSegmentToNeigh(rID, cID, neigh) and not self.amImalicious: @@ -457,7 +456,7 @@ class Validator: t = tries if self.columnIDs: cID = random.choice(self.columnIDs) - rID = random.randrange(0, self.shape.blockSize) + rID = random.randrange(0, self.shape.blockSizeC) if self.block.getSegment(rID, cID) : neigh = random.choice(list(self.columnNeighbors[cID].values())) if self.checkSegmentToNeigh(rID, cID, neigh) and not self.amImalicious: @@ -576,4 +575,4 @@ class Validator: if a == e: validated+=1 - return arrived, expected, validated + return arrived, expected, validated \ No newline at end of file diff --git a/DAS/visualizer.py b/DAS/visualizer.py index 02bb432..12b3d31 100644 --- a/DAS/visualizer.py +++ b/DAS/visualizer.py @@ -33,12 +33,12 @@ class Visualizer: tree = ET.parse(os.path.join(self.folderPath, filename)) root = tree.getroot() run = int(root.find('run').text) - blockSize = int(root.find('blockSize').text) + blockSize = int(root.find('blockSizeR').text) # TODO: maybe we want both dimensions failureRate = int(root.find('failureRate').text) numberNodes = int(root.find('numberNodes').text) class1ratio = float(root.find('class1ratio').text) netDegree = int(root.find('netDegree').text) - chi = int(root.find('chi').text) + chi = int(root.find('chiR').text) # TODO: maybe we want both dimensions vpn1 = int(root.find('vpn1').text) vpn2 = int(root.find('vpn2').text) bwUplinkProd = int(root.find('bwUplinkProd').text) @@ -274,4 +274,4 @@ class Visualizer: plt.ylabel('Price') #Test - plt.show() + plt.show() \ No newline at end of file diff --git a/DAS/visualizor.py b/DAS/visualizor.py index 50ed89f..fa4676d 100644 --- a/DAS/visualizor.py +++ b/DAS/visualizor.py @@ -1,6 +1,7 @@ #!/bin/python3 import matplotlib.pyplot as plt +import numpy as np import os def plotData(conf): @@ -87,8 +88,8 @@ class Visualizor: """Plots the restoreRowCount for each node""" conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" + conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Restore Row Count for Each Node" conf["type"] = "individual_bar" conf["legLoc"] = 1 @@ -107,8 +108,8 @@ class Visualizor: """Plots the restoreColumnCount for each node""" conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" + conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Restore Column Count for Each Node" conf["type"] = "individual_bar" conf["legLoc"] = 1 @@ -127,15 +128,15 @@ class Visualizor: """Plots the percentage sampleRecv for each node""" conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" + conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Percentage of Samples Received by Nodes" conf["type"] = "individual_bar" conf["legLoc"] = 1 conf["desLoc"] = 1 conf["xlabel"] = "Nodes" conf["ylabel"] = "Percentage of samples received (%)" - total_samples = result.shape.blockSize * result.shape.blockSize + total_samples = result.shape.blockSizeR * result.shape.blockSizeC percentage_data = [(count / total_samples) * 100 for count in result.sampleRecvCount] conf["data"] = percentage_data conf["xdots"] = range(result.shape.numberNodes) @@ -149,8 +150,8 @@ class Visualizor: """Plots the missing samples in the network""" conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" + conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Missing Samples" conf["type"] = "plot" conf["legLoc"] = 1 @@ -177,8 +178,8 @@ class Visualizor: vector3 = [x * 100 for x in result.metrics["progress"]["samples received"]] conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" + conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Nodes/validators ready" conf["type"] = "plot" conf["legLoc"] = 2 @@ -209,8 +210,8 @@ class Visualizor: vector3[i] = (vector3[i] * 8 * (1000/self.config.stepDuration) * self.config.segmentSize) / 1000000 conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" + conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Sent data" conf["type"] = "plot" conf["legLoc"] = 2 @@ -239,8 +240,8 @@ class Visualizor: vector2[i] = (vector2[i] * 8 * (1000/self.config.stepDuration) * self.config.segmentSize) / 1000000 conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" + conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Received data" conf["type"] = "plot" conf["legLoc"] = 2 @@ -269,8 +270,8 @@ class Visualizor: vector2[i] = (vector2[i] * 8 * (1000/self.config.stepDuration) * self.config.segmentSize) / 1000000 conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" + conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Duplicated data" conf["type"] = "plot" conf["legLoc"] = 2 @@ -294,10 +295,14 @@ class Visualizor: """Plots the percentage of nodes ready in the network""" vector1 = result.metrics["rowDist"] vector2 = result.metrics["columnDist"] + if len(vector1) > len(vector2): + vector2 += [np.nan] * (len(vector1) - len(vector2)) + elif len(vector1) < len(vector2): + vector1 += [np.nan] * (len(vector2) - len(vector1)) conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" + conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Row/Column distribution" conf["type"] = "grouped_bar" conf["legLoc"] = 2 @@ -311,7 +316,7 @@ class Visualizor: conf["path"] = plotPath+"/RowColDist.png" maxi = 0 for v in conf["data"]: - if max(v) > maxi: + if np.nanmax(v) > maxi: maxi = max(v) conf["yaxismax"] = maxi plotData(conf) @@ -321,8 +326,8 @@ class Visualizor: """Plots the number of messages sent by all nodes""" conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" + conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Number of Messages Sent by Nodes" conf["type"] = "individual_bar" conf["legLoc"] = 1 @@ -341,8 +346,8 @@ class Visualizor: """Plots the number of messages received by all nodes""" conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ - +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" + conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Number of Messages Received by Nodes" conf["type"] = "individual_bar" conf["legLoc"] = 1 @@ -356,4 +361,3 @@ class Visualizor: conf["yaxismax"] = maxi plotData(conf) print("Plot %s created." % conf["path"]) - diff --git a/smallConf.py b/smallConf.py index e5f6ccd..a92f76d 100644 --- a/smallConf.py +++ b/smallConf.py @@ -57,27 +57,21 @@ failureModels = ["random"] failureRates = [0] # Percentage of nodes that are considered malicious -maliciousNodes = [95] +maliciousNodes = [0] # Parameter to determine whether to randomly assign malicious nodes or not # If True, the malicious nodes will be assigned randomly; if False, a predefined pattern may be used randomizeMaliciousNodes = True -# Block size in one dimension in segments. Block is blockSizes * blockSizes segments. -blockSizes = [128] - # Per-topic mesh neighborhood size netDegrees = range(8, 9, 2) -# number of rows and columns a validator is interested in -chis = range(2, 3, 2) - # ratio of class1 nodes (see below for parameters per class) class1ratios = [0.8] # Number of validators per beacon node -validatorsPerNode1 = [10] -validatorsPerNode2 = [250] +validatorsPerNode1 = [1] +validatorsPerNode2 = [1] # Set uplink bandwidth in megabits/second bwUplinksProd = [200] @@ -108,10 +102,17 @@ diagnostics = False # True to save git diff and git commit saveGit = False +blockSizeR =[128] +blockSizeC = [64] +blockSizeRK = [64] +blockSizeCK = [64] +chiR = [2] +chiC = [2] + def nextShape(): - for run, fm, fr, mn, class1ratio, chi, vpn1, vpn2, blockSize, nn, netDegree, bwUplinkProd, bwUplink1, bwUplink2 in itertools.product( - runs, failureModels, failureRates, maliciousNodes, class1ratios, chis, validatorsPerNode1, validatorsPerNode2, blockSizes, numberNodes, netDegrees, bwUplinksProd, bwUplinks1, bwUplinks2): + for blckSizeR, blckSizeRK, blckSizeC, blckSizeCK, run, fm, fr, mn, class1ratio, chR, chC, vpn1, vpn2, nn, netDegree, bwUplinkProd, bwUplink1, bwUplink2 in itertools.product( + blockSizeR, blockSizeRK, blockSizeC, blockSizeCK, runs, failureModels, failureRates, maliciousNodes, class1ratios, chiR, chiC, validatorsPerNode1, validatorsPerNode2, numberNodes, netDegrees, bwUplinksProd, bwUplinks1, bwUplinks2): # Network Degree has to be an even number if netDegree % 2 == 0: - shape = Shape(blockSize, nn, fm, fr, mn, class1ratio, chi, vpn1, vpn2, netDegree, bwUplinkProd, bwUplink1, bwUplink2, run) - yield shape + shape = Shape(blckSizeR, blckSizeRK, blckSizeC, blckSizeCK, nn, fm, fr, mn, class1ratio, chR, chC, vpn1, vpn2, netDegree, bwUplinkProd, bwUplink1, bwUplink2, run) + yield shape \ No newline at end of file From 6acf8a8285649a03f598e8de1eb8a2a24df2f908 Mon Sep 17 00:00:00 2001 From: Sudipta Basak Date: Sun, 18 Feb 2024 14:22:57 +0100 Subject: [PATCH 06/21] fixed columns array size --- DAS/simulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DAS/simulator.py b/DAS/simulator.py index 50b7289..f4be995 100644 --- a/DAS/simulator.py +++ b/DAS/simulator.py @@ -59,7 +59,7 @@ class Simulator: rows = list(range(self.shape.blockSizeC)) * (int(totalRows/self.shape.blockSizeC)+1) columns = list(range(self.shape.blockSizeR)) * (int(totalColumns/self.shape.blockSizeR)+1) rows = rows[0:totalRows] - columns = columns[0:totalRows] + columns = columns[0:totalColumns] random.shuffle(rows) random.shuffle(columns) offsetR = lightVal*self.shape.chiR From 88f8d1f1c4b771614874251382f4116c459a10d5 Mon Sep 17 00:00:00 2001 From: Sudipta Basak Date: Sun, 18 Feb 2024 16:31:10 +0100 Subject: [PATCH 07/21] README.md Fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 97846ce..e4e9841 100644 --- a/README.md +++ b/README.md @@ -22,5 +22,5 @@ $ pip3 install -r DAS/requirements.txt ## Run the simulator ``` -$ python3 study.py config.das +$ python3 study.py smallConf.py ``` From 94b9f4bdaeef26629540f1bd79fe3125ce5b2592 Mon Sep 17 00:00:00 2001 From: Arunima Chaudhuri Date: Sun, 18 Feb 2024 22:16:16 +0530 Subject: [PATCH 08/21] add expectd line in graph&rem evenLineDist in conf Signed-off-by: Arunima Chaudhuri --- DAS/simulator.py | 7 +++++-- DAS/visualizor.py | 47 +++++++++++++++++++++++++++++++---------------- smallConf.py | 8 ++------ 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/DAS/simulator.py b/DAS/simulator.py index 50b7289..fddaaa9 100644 --- a/DAS/simulator.py +++ b/DAS/simulator.py @@ -47,7 +47,8 @@ class Simulator: """It initializes all the validators in the network.""" self.glob = Observer(self.logger, self.shape) self.validators = [] - if self.config.evenLineDistribution: + evenLineDistribution = False + if evenLineDistribution: lightNodes = int(self.shape.numberNodes * self.shape.class1ratio) heavyNodes = self.shape.numberNodes - lightNodes @@ -94,7 +95,7 @@ class Simulator: else: amImalicious_value = 0 - if self.config.evenLineDistribution: + if evenLineDistribution: if i < int(lightVal/self.shape.vpn1): # First start with the light nodes startR = i *self.shape.chiR*self.shape.vpn1 endR = (i+1)*self.shape.chiR*self.shape.vpn1 @@ -263,6 +264,8 @@ class Simulator: steps = 0 while(True): missingVector.append(missingSamples) + self.logger.debug("Expected Samples: %d" % expected, extra=self.format) + self.logger.debug("Missing Samples: %d" % missingSamples, extra=self.format) oldMissingSamples = missingSamples self.logger.debug("PHASE SEND %d" % steps, extra=self.format) for i in range(0,self.shape.numberNodes): diff --git a/DAS/visualizor.py b/DAS/visualizor.py index fa4676d..6543b30 100644 --- a/DAS/visualizor.py +++ b/DAS/visualizor.py @@ -14,14 +14,19 @@ def plotData(conf): xDes = conf["xdots"][-1] * 0.6 props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) plt.text(xDes, conf["yaxismax"]/3, conf["textBox"], fontsize=10, verticalalignment='top', bbox=props) - if conf["type"] == "plot": + if conf["type"] == "plot" or conf["type"] == "plot_with_1line": for i in range(len(conf["data"])): plt.plot(conf["xdots"], conf["data"][i], conf["colors"][i], label=conf["labels"][i]) - elif conf["type"] == "individual_bar": + elif conf["type"] == "individual_bar" or conf["type"] == "individual_bar_with_2line": plt.bar(conf["xdots"], conf["data"]) elif conf["type"] == "grouped_bar": for i in range(len(conf["data"])): plt.bar(conf["xdots"], conf["data"][i], label=conf["labels"][i]) + if conf["type"] == "individual_bar_with_2line": + plt.axhline(y = conf["expected_value1"], color='r', linestyle='--', label='Expected Value for class 1 nodes') + plt.axhline(y = conf["expected_value2"], color='g', linestyle='--', label='Expected Value for class 2 nodes') + if conf["type"] == "plot_with_1line": + plt.axhline(y = conf["expected_value"], color='g', linestyle='--', label='Expected Value') plt.title(conf["title"]) plt.ylabel(conf["ylabel"]) plt.xlabel(conf["xlabel"]) @@ -88,7 +93,7 @@ class Visualizor: """Plots the restoreRowCount for each node""" conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Restore Row Count for Each Node" conf["type"] = "individual_bar" @@ -108,7 +113,7 @@ class Visualizor: """Plots the restoreColumnCount for each node""" conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Restore Column Count for Each Node" conf["type"] = "individual_bar" @@ -128,10 +133,10 @@ class Visualizor: """Plots the percentage sampleRecv for each node""" conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Percentage of Samples Received by Nodes" - conf["type"] = "individual_bar" + conf["type"] = "individual_bar_with_2line" conf["legLoc"] = 1 conf["desLoc"] = 1 conf["xlabel"] = "Nodes" @@ -142,7 +147,15 @@ class Visualizor: conf["xdots"] = range(result.shape.numberNodes) conf["path"] = plotPath + "/sampleRecv.png" maxi = max(conf["data"]) - conf["yaxismax"] = maxi + conf["yaxismax"] = maxi * 1.1 + expected_percentage1 = (result.shape.vpn1 * (result.shape.blockSizeR * result.shape.chiR + result.shape.blockSizeC * result.shape.chiC) * 100)/total_samples + expected_percentage2 = (result.shape.vpn2 * (result.shape.blockSizeR * result.shape.chiR + result.shape.blockSizeC * result.shape.chiC) * 100)/total_samples + if expected_percentage1 > 100: + expected_percentage1 = 100 + if expected_percentage2 > 100: + expected_percentage2 = 100 + conf["expected_value1"] = expected_percentage1 + conf["expected_value2"] = expected_percentage2 plotData(conf) print("Plot %s created." % conf["path"]) @@ -150,10 +163,10 @@ class Visualizor: """Plots the missing samples in the network""" conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Missing Samples" - conf["type"] = "plot" + conf["type"] = "plot_with_1line" conf["legLoc"] = 1 conf["desLoc"] = 1 conf["colors"] = ["m-"] @@ -168,6 +181,8 @@ class Visualizor: if max(v) > maxi: maxi = max(v) conf["yaxismax"] = maxi + x = result.shape.blockSizeR * result.shape.chiR + result.shape.blockSizeC * result.shape.chiC + conf["expected_value"] = (result.shape.numberNodes - 1) * (result.shape.class1ratio * result.shape.vpn1 * x + (1 - result.shape.class1ratio) * result.shape.vpn2 * x) plotData(conf) print("Plot %s created." % conf["path"]) @@ -178,7 +193,7 @@ class Visualizor: vector3 = [x * 100 for x in result.metrics["progress"]["samples received"]] conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Nodes/validators ready" conf["type"] = "plot" @@ -210,7 +225,7 @@ class Visualizor: vector3[i] = (vector3[i] * 8 * (1000/self.config.stepDuration) * self.config.segmentSize) / 1000000 conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Sent data" conf["type"] = "plot" @@ -240,7 +255,7 @@ class Visualizor: vector2[i] = (vector2[i] * 8 * (1000/self.config.stepDuration) * self.config.segmentSize) / 1000000 conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Received data" conf["type"] = "plot" @@ -270,7 +285,7 @@ class Visualizor: vector2[i] = (vector2[i] * 8 * (1000/self.config.stepDuration) * self.config.segmentSize) / 1000000 conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Duplicated data" conf["type"] = "plot" @@ -301,7 +316,7 @@ class Visualizor: vector1 += [np.nan] * (len(vector2) - len(vector1)) conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Row/Column distribution" conf["type"] = "grouped_bar" @@ -326,7 +341,7 @@ class Visualizor: """Plots the number of messages sent by all nodes""" conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Number of Messages Sent by Nodes" conf["type"] = "individual_bar" @@ -346,7 +361,7 @@ class Visualizor: """Plots the number of messages received by all nodes""" conf = {} text = str(result.shape).split("-") - conf["textBox"] = "Block SizeR: "+text[2]+"\nBlock SizeC: "+text[6]+"\nNumber of nodes: "+text[10]\ + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" conf["title"] = "Number of Messages Received by Nodes" conf["type"] = "individual_bar" diff --git a/smallConf.py b/smallConf.py index a92f76d..e4c91aa 100644 --- a/smallConf.py +++ b/smallConf.py @@ -40,10 +40,6 @@ logLevel = logging.INFO # for more details, see joblib.Parallel numJobs = -1 -# distribute rows/columns evenly between validators (True) -# or generate it using local randomness (False) -evenLineDistribution = True - # Number of simulation runs with the same parameters for statistical relevance runs = [1] @@ -64,7 +60,7 @@ maliciousNodes = [0] randomizeMaliciousNodes = True # Per-topic mesh neighborhood size -netDegrees = range(8, 9, 2) +netDegrees = [8] # ratio of class1 nodes (see below for parameters per class) class1ratios = [0.8] @@ -102,7 +98,7 @@ diagnostics = False # True to save git diff and git commit saveGit = False -blockSizeR =[128] +blockSizeR = [128] blockSizeC = [64] blockSizeRK = [64] blockSizeCK = [64] From d81a8c25374d08042a2446e33e3c98efba043f57 Mon Sep 17 00:00:00 2001 From: Arunima Chaudhuri Date: Sun, 18 Feb 2024 22:51:19 +0530 Subject: [PATCH 09/21] fix label Signed-off-by: Arunima Chaudhuri --- DAS/visualizor.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/DAS/visualizor.py b/DAS/visualizor.py index 6543b30..e706ae4 100644 --- a/DAS/visualizor.py +++ b/DAS/visualizor.py @@ -23,10 +23,10 @@ def plotData(conf): for i in range(len(conf["data"])): plt.bar(conf["xdots"], conf["data"][i], label=conf["labels"][i]) if conf["type"] == "individual_bar_with_2line": - plt.axhline(y = conf["expected_value1"], color='r', linestyle='--', label='Expected Value for class 1 nodes') - plt.axhline(y = conf["expected_value2"], color='g', linestyle='--', label='Expected Value for class 2 nodes') + plt.axhline(y = conf["expected_value1"], color='r', linestyle='--', label=conf["line_label1"]) + plt.axhline(y = conf["expected_value2"], color='g', linestyle='--', label=conf["line_label2"]) if conf["type"] == "plot_with_1line": - plt.axhline(y = conf["expected_value"], color='g', linestyle='--', label='Expected Value') + plt.axhline(y = conf["expected_value"], color='g', linestyle='--', label=conf["line_label"]) plt.title(conf["title"]) plt.ylabel(conf["ylabel"]) plt.xlabel(conf["xlabel"]) @@ -147,7 +147,7 @@ class Visualizor: conf["xdots"] = range(result.shape.numberNodes) conf["path"] = plotPath + "/sampleRecv.png" maxi = max(conf["data"]) - conf["yaxismax"] = maxi * 1.1 + # conf["yaxismax"] = maxi * 1.1 expected_percentage1 = (result.shape.vpn1 * (result.shape.blockSizeR * result.shape.chiR + result.shape.blockSizeC * result.shape.chiC) * 100)/total_samples expected_percentage2 = (result.shape.vpn2 * (result.shape.blockSizeR * result.shape.chiR + result.shape.blockSizeC * result.shape.chiC) * 100)/total_samples if expected_percentage1 > 100: @@ -156,6 +156,9 @@ class Visualizor: expected_percentage2 = 100 conf["expected_value1"] = expected_percentage1 conf["expected_value2"] = expected_percentage2 + conf["line_label1"] = "Expected Value for class 1 nodes" + conf["line_label2"] = "Expected Value for class 1 nodes" + conf["yaxismax"] = max(expected_percentage1, expected_percentage2) * 1.05 plotData(conf) print("Plot %s created." % conf["path"]) @@ -183,6 +186,7 @@ class Visualizor: conf["yaxismax"] = maxi x = result.shape.blockSizeR * result.shape.chiR + result.shape.blockSizeC * result.shape.chiC conf["expected_value"] = (result.shape.numberNodes - 1) * (result.shape.class1ratio * result.shape.vpn1 * x + (1 - result.shape.class1ratio) * result.shape.vpn2 * x) + conf["line_label"] = "Total samples to deliver" plotData(conf) print("Plot %s created." % conf["path"]) From 4ef26176748397f5c2c17ba0150cf33c886d64fd Mon Sep 17 00:00:00 2001 From: Arunima Chaudhuri Date: Mon, 19 Feb 2024 14:29:23 +0530 Subject: [PATCH 10/21] correct class label in graph Signed-off-by: Arunima Chaudhuri --- DAS/visualizor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DAS/visualizor.py b/DAS/visualizor.py index e706ae4..fbc62d2 100644 --- a/DAS/visualizor.py +++ b/DAS/visualizor.py @@ -157,7 +157,7 @@ class Visualizor: conf["expected_value1"] = expected_percentage1 conf["expected_value2"] = expected_percentage2 conf["line_label1"] = "Expected Value for class 1 nodes" - conf["line_label2"] = "Expected Value for class 1 nodes" + conf["line_label2"] = "Expected Value for class 2 nodes" conf["yaxismax"] = max(expected_percentage1, expected_percentage2) * 1.05 plotData(conf) print("Plot %s created." % conf["path"]) From be0ce303c6f7f152c0e1b4e5da31d1957ddd02a8 Mon Sep 17 00:00:00 2001 From: Sudipta Basak Date: Mon, 19 Feb 2024 23:20:53 +0100 Subject: [PATCH 11/21] Added New Plot 'No. of Repaired Samples by each Node' --- DAS/block.py | 8 ++++++-- DAS/results.py | 2 ++ DAS/validator.py | 7 +++++-- DAS/visualizor.py | 21 +++++++++++++++++++++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/DAS/block.py b/DAS/block.py index ef3f4f5..6d5c1d3 100644 --- a/DAS/block.py +++ b/DAS/block.py @@ -50,12 +50,14 @@ class Block: """ line = self.data[id::self.blockSizeR] success = line.count(1) + repairedSamples = 0 if success >= self.blockSizeCK: ret = ~line self.data[id::self.blockSizeR] = 1 + repairedSamples = len(line) - success else: ret = zeros(self.blockSizeC) - return ret + return ret, repairedSamples def getRow(self, rowID): """It returns the block row corresponding to rowID.""" @@ -71,12 +73,14 @@ class Block: """ line = self.data[id*self.blockSizeR:(id+1)*self.blockSizeR] success = line.count(1) + repairedSamples = 0 if success >= self.blockSizeRK: ret = ~line self.data[id*self.blockSizeR:(id+1)*self.blockSizeR] = 1 + repairedSamples = len(line) - success else: ret = zeros(self.blockSizeR) - return ret + return ret, repairedSamples def print(self): """It prints the block in the terminal (outside of the logger rules)).""" diff --git a/DAS/results.py b/DAS/results.py index 6fbf3a4..2cab701 100644 --- a/DAS/results.py +++ b/DAS/results.py @@ -22,6 +22,7 @@ class Result: self.sampleRecvCount = [0] * shape.numberNodes self.restoreRowCount = [0] * shape.numberNodes self.restoreColumnCount = [0] * shape.numberNodes + self.repairedSampleCount = [0] * shape.numberNodes def copyValidators(self, validators): """Copy information from simulator.validators to result.""" @@ -32,6 +33,7 @@ class Result: self.sampleRecvCount[i] = validators[i].sampleRecvCount self.restoreRowCount[i] = validators[i].restoreRowCount self.restoreColumnCount[i] = validators[i].restoreColumnCount + self.repairedSampleCount[i] = validators[i].repairedSampleCount def populate(self, shape, config, missingVector): """It populates part of the result data inside a vector.""" diff --git a/DAS/validator.py b/DAS/validator.py index ae99d6f..82bb050 100644 --- a/DAS/validator.py +++ b/DAS/validator.py @@ -62,6 +62,7 @@ class Validator: self.sampleRecvCount = 0 self.restoreRowCount = 0 self.restoreColumnCount = 0 + self.repairedSampleCount = 0 self.logger = logger if self.shape.chiR < 1 and self.shape.chiC < 1: self.logger.error("Chi has to be greater than 0", extra=self.format) @@ -518,7 +519,8 @@ class Validator: def restoreRow(self, id): """Restore a given row if repairable.""" - rep = self.block.repairRow(id) + rep, repairedSamples = self.block.repairRow(id) + self.repairedSampleCount += repairedSamples if (rep.any()): # If operation is based on send queues, segments should # be queued after successful repair. @@ -538,7 +540,8 @@ class Validator: def restoreColumn(self, id): """Restore a given column if repairable.""" - rep = self.block.repairColumn(id) + rep, repairedSamples = self.block.repairColumn(id) + self.repairedSampleCount += repairedSamples if (rep.any()): # If operation is based on send queues, segments should # be queued after successful repair. diff --git a/DAS/visualizor.py b/DAS/visualizor.py index fbc62d2..60ddfe3 100644 --- a/DAS/visualizor.py +++ b/DAS/visualizor.py @@ -86,6 +86,7 @@ class Visualizor: self.plotSentData(result, plotPath) self.plotRecvData(result, plotPath) self.plotDupData(result, plotPath) + self.plotSamplesRepaired(result, plotPath) if self.config.saveRCdist: self.plotRowCol(result, plotPath) @@ -380,3 +381,23 @@ class Visualizor: conf["yaxismax"] = maxi plotData(conf) print("Plot %s created." % conf["path"]) + + def plotSamplesRepaired(self, result, plotPath): + """Plots the number of samples repaired by all nodes""" + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "Number of Samples Repaired by Nodes" + conf["type"] = "individual_bar" + conf["legLoc"] = 1 + conf["desLoc"] = 1 + conf["xlabel"] = "Nodes" + conf["ylabel"] = "Number of Samples Repaired" + conf["data"] = result.repairedSampleCount + conf["xdots"] = range(result.shape.numberNodes) + conf["path"] = plotPath + "/repairedSampleCount.png" + maxi = max(conf["data"]) + conf["yaxismax"] = maxi + plotData(conf) + print("Plot %s created." % conf["path"]) From 11afac03b993cd9c83cc11f8dabafe6fa29e7881 Mon Sep 17 00:00:00 2001 From: Sudipta Basak Date: Wed, 21 Feb 2024 12:26:38 +0100 Subject: [PATCH 12/21] Added box plot for messages received & samples received by nodes --- DAS/results.py | 2 ++ DAS/visualizor.py | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/DAS/results.py b/DAS/results.py index 2cab701..f679702 100644 --- a/DAS/results.py +++ b/DAS/results.py @@ -23,6 +23,8 @@ class Result: self.restoreRowCount = [0] * shape.numberNodes self.restoreColumnCount = [0] * shape.numberNodes self.repairedSampleCount = [0] * shape.numberNodes + self.numberNodes = shape.numberNodes + self.class1ratio = shape.class1ratio def copyValidators(self, validators): """Copy information from simulator.validators to result.""" diff --git a/DAS/visualizor.py b/DAS/visualizor.py index 60ddfe3..8ab83a0 100644 --- a/DAS/visualizor.py +++ b/DAS/visualizor.py @@ -34,6 +34,20 @@ def plotData(conf): plt.legend(loc=conf["legLoc"]) plt.savefig(conf["path"], bbox_inches="tight") +def plotBoxData(conf): + plt.clf() + plt.grid(True) + props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) + num_boxes = len(conf["data"]) + positions = np.arange(num_boxes) + plt.text(0.05, 0.05, conf["textBox"], fontsize=10, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props) + plt.boxplot(conf["data"], patch_artist=True, showmeans=True, meanline=True, positions=positions) + plt.title(conf["title"], fontsize=14) + plt.ylabel(conf["ylabel"], fontsize=12) + plt.xlabel(conf["xlabel"], fontsize=12) + plt.xticks(fontsize=10) + plt.yticks(fontsize=10) + plt.savefig(conf["path"], bbox_inches="tight") class Visualizor: """This class helps the visualization of the results""" @@ -80,7 +94,9 @@ class Visualizor: self.plotRestoreColumnCount(result, plotPath) self.plotMessagesSent(result, plotPath) self.plotMessagesRecv(result, plotPath) + self.plotBoxMessagesRecv(result, plotPath) self.plotSampleRecv(result, plotPath) + self.plotBoxSampleRecv(result, plotPath) self.plotMissingSamples(result, plotPath) self.plotProgress(result, plotPath) self.plotSentData(result, plotPath) @@ -163,6 +179,25 @@ class Visualizor: plotData(conf) print("Plot %s created." % conf["path"]) + def plotBoxSampleRecv(self, result, plotPath): + """Box Plot of the sampleRecv for each node""" + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "Number of Samples Received by Nodes" + conf["type"] = "individual_bar_with_2line" + conf["legLoc"] = 1 + conf["desLoc"] = 1 + conf["xlabel"] = "Node Type" + conf["ylabel"] = "Number of samples received (%)" + n1 = int(result.numberNodes * result.class1ratio) + conf["data"] = [result.sampleRecvCount[1: n1], result.sampleRecvCount[n1: ]] + conf["xdots"] = range(result.shape.numberNodes) + conf["path"] = plotPath + "/box_sampleRecv.png" + plotBoxData(conf) + print("Plot %s created." % conf["path"]) + def plotMissingSamples(self, result, plotPath): """Plots the missing samples in the network""" conf = {} @@ -381,6 +416,27 @@ class Visualizor: conf["yaxismax"] = maxi plotData(conf) print("Plot %s created." % conf["path"]) + + def plotBoxMessagesRecv(self, result, plotPath): + """Plots the number of messages received by all nodes""" + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "Number of Messages Received by Nodes" + conf["type"] = "individual_bar" + conf["legLoc"] = 1 + conf["desLoc"] = 1 + conf["xlabel"] = "Node Type" + conf["ylabel"] = "Number of Messages Received" + n1 = int(result.numberNodes * result.class1ratio) + conf["data"] = [result.msgRecvCount[1: n1], result.msgRecvCount[n1: ]] + conf["xdots"] = range(result.shape.numberNodes) + conf["path"] = plotPath + "/box_messagesRecv.png" + maxi = max(conf["data"]) + conf["yaxismax"] = maxi + plotBoxData(conf) + print("Plot %s created." % conf["path"]) def plotSamplesRepaired(self, result, plotPath): """Plots the number of samples repaired by all nodes""" From 7c33fec8da34e2fd3094132f9c5793f6442608d0 Mon Sep 17 00:00:00 2001 From: Sudipta Basak Date: Wed, 21 Feb 2024 12:54:02 +0100 Subject: [PATCH 13/21] Added Box Plot for Messages Sent by Each Node --- DAS/visualizor.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/DAS/visualizor.py b/DAS/visualizor.py index 8ab83a0..71cd0f6 100644 --- a/DAS/visualizor.py +++ b/DAS/visualizor.py @@ -93,6 +93,7 @@ class Visualizor: self.plotRestoreRowCount(result, plotPath) self.plotRestoreColumnCount(result, plotPath) self.plotMessagesSent(result, plotPath) + self.plotBoxMessagesSent(result, plotPath) self.plotMessagesRecv(result, plotPath) self.plotBoxMessagesRecv(result, plotPath) self.plotSampleRecv(result, plotPath) @@ -396,6 +397,21 @@ class Visualizor: conf["yaxismax"] = maxi plotData(conf) print("Plot %s created." % conf["path"]) + + def plotBoxMessagesSent(self, result, plotPath): + """Box Plot of the number of messages sent by all nodes""" + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "Number of Messages Sent by Nodes" + conf["xlabel"] = "Node Type" + conf["ylabel"] = "Number of Messages Sent" + n1 = int(result.numberNodes * result.class1ratio) + conf["data"] = [result.msgSentCount[1: n1], result.msgSentCount[n1: ]] + conf["path"] = plotPath + "/box_messagesSent.png" + plotBoxData(conf) + print("Plot %s created." % conf["path"]) def plotMessagesRecv(self, result, plotPath): """Plots the number of messages received by all nodes""" From 575c55480fb5ec9d0abda225a357ab0a4b5bc173 Mon Sep 17 00:00:00 2001 From: Arunima Chaudhuri Date: Wed, 28 Feb 2024 22:14:55 +0530 Subject: [PATCH 14/21] add boxen & ecdf plots Signed-off-by: Arunima Chaudhuri --- DAS/visualizer.py | 15 --- DAS/visualizor.py | 268 ++++++++++++++++++++++++++++++++++++++++++++++ smallConf.py | 26 ++--- 3 files changed, 281 insertions(+), 28 deletions(-) diff --git a/DAS/visualizer.py b/DAS/visualizer.py index 12b3d31..db2b021 100644 --- a/DAS/visualizer.py +++ b/DAS/visualizer.py @@ -241,21 +241,6 @@ class Visualizer: plt.savefig(filename) plt.clf() - def plotHist(self, bandwidth): - """Plot Bandwidth Frequency Histogram""" - plt.hist(bandwidth, bins=5) - plt.xlabel('Bandwidth') - plt.ylabel('Frequency') - plt.title('Bandwidth Histogram') - - """Create the directory if it doesn't exist already""" - histogramFolder = self.folderPath + '/histogram' - if not os.path.exists(histogramFolder): - os.makedirs(histogramFolder) - filename = os.path.join(histogramFolder, 'histogram.png') - plt.savefig(filename) - plt.clf() - def plotCandleStick(self, TX_prod, TX_avg, TX_max): #x-axis corresponding to steps steps = range(len(TX_prod)) diff --git a/DAS/visualizor.py b/DAS/visualizor.py index 71cd0f6..0bd1721 100644 --- a/DAS/visualizor.py +++ b/DAS/visualizor.py @@ -1,6 +1,7 @@ #!/bin/python3 import matplotlib.pyplot as plt +import seaborn as sns import numpy as np import os @@ -104,9 +105,276 @@ class Visualizor: self.plotRecvData(result, plotPath) self.plotDupData(result, plotPath) self.plotSamplesRepaired(result, plotPath) + self.plotBoxSamplesRepaired(result, plotPath) + self.plotBoxRowCol(result, plotPath) + self.plotBoxenMessagesRecv(result, plotPath) + self.plotBoxenMessagesSent(result, plotPath) + self.plotBoxenSamplesRecv(result, plotPath) + self.plotBoxenSamplesRepaired(result, plotPath) + self.plotBoxenRowColDist(result, plotPath) + + self.plotECDFSamplesRepaired(result, plotPath) + self.plotECDFRowColDist(result, plotPath) + self.plotECDFSamplesReceived(result, plotPath) + self.plotECDFMessagesRecv(result, plotPath) + self.plotECDFMessagesSent(result, plotPath) if self.config.saveRCdist: self.plotRowCol(result, plotPath) + + def plotECDFMessagesSent(self, result, plotPath): + """Plots the ECDF of messages sent by all nodes using seaborn's ecdfplot""" + plt.clf() + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "ECDF of Messages Sent by Nodes" + conf["xlabel"] = "Number of Messages Sent" + conf["ylabel"] = "ECDF" + sns.ecdfplot(data=result.msgSentCount) + plt.xlabel(conf["xlabel"]) + plt.ylabel(conf["ylabel"]) + plt.title(conf["title"]) + plt.xlim(left=0, right=max(result.msgSentCount) * 1.1) + plt.savefig(plotPath + "/ecdf_messagesSent.png", bbox_inches="tight") + print("Plot %s created." % (plotPath + "/ecdf_messagesSent.png")) + + def plotECDFMessagesRecv(self, result, plotPath): + """Plots the ECDF of messages received by all nodes using seaborn's ecdfplot""" + plt.clf() + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "ECDF of Messages Received by Nodes" + conf["xlabel"] = "Number of Messages Received" + conf["ylabel"] = "ECDF" + sns.ecdfplot(data=result.msgRecvCount) + plt.xlabel(conf["xlabel"]) + plt.ylabel(conf["ylabel"]) + plt.title(conf["title"]) + plt.xlim(left=0, right=max(result.msgRecvCount) * 1.1) + plt.savefig(plotPath + "/ecdf_messagesRecv.png", bbox_inches="tight") + print("Plot %s created." % (plotPath + "/ecdf_messagesRecv.png")) + + def plotECDFSamplesReceived(self, result, plotPath): + """Plots the ECDF of samples received by all nodes using seaborn's ecdfplot""" + plt.clf() + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "ECDF of Samples Received by Nodes" + conf["xlabel"] = "Number of Samples Received" + conf["ylabel"] = "ECDF" + sns.ecdfplot(data=result.sampleRecvCount) + plt.xlabel(conf["xlabel"]) + plt.ylabel(conf["ylabel"]) + plt.title(conf["title"]) + plt.xlim(left=0, right=max(result.sampleRecvCount) * 1.1) + plt.savefig(plotPath + "/ecdf_samplesReceived.png", bbox_inches="tight") + print("Plot %s created." % (plotPath + "/ecdf_samplesReceived.png")) + + def plotECDFRowColDist(self, result, plotPath): + """Plots the ECDF of row col distance by all nodes using seaborn's ecdfplot""" + plt.clf() + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "ECDF of Row-Col Distance by Nodes" + conf["xlabel"] = "Row-Col Distance" + conf["ylabel"] = "ECDF" + vector1 = result.metrics["rowDist"] + vector2 = result.metrics["columnDist"] + if len(vector1) > len(vector2): + vector2 += [np.nan] * (len(vector1) - len(vector2)) + elif len(vector1) < len(vector2): + vector1 += [np.nan] * (len(vector2) - len(vector1)) + n1 = int(result.numberNodes * result.class1ratio) + conf["data"] = [vector1, vector2] + sns.ecdfplot(data=conf["data"]) + plt.xlabel(conf["xlabel"]) + plt.ylabel(conf["ylabel"]) + plt.title(conf["title"]) + plt.xlim(left=0, right=max(max(vector1), max(vector2)) * 1.1) + plt.savefig(plotPath + "/ecdf_rowColDist.png", bbox_inches="tight") + print("Plot %s created." % (plotPath + "/ecdf_rowColDist.png")) + + def plotECDFSamplesRepaired(self, result, plotPath): + """Plots the ECDF of samples repaired by all nodes using seaborn's ecdfplot""" + plt.clf() + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "ECDF of Samples Repaired by Nodes" + conf["xlabel"] = "Number of Samples Repaired" + conf["ylabel"] = "ECDF" + sns.ecdfplot(data=result.repairedSampleCount) + plt.xlabel(conf["xlabel"]) + plt.ylabel(conf["ylabel"]) + plt.title(conf["title"]) + plt.xlim(left=0, right=max(result.repairedSampleCount) * 1.1) + plt.savefig(plotPath + "/ecdf_samplesRepaired.png", bbox_inches="tight") + print("Plot %s created." % (plotPath + "/ecdf_samplesRepaired.png")) + + + + + def plotBoxenSamplesRecv(self, result, plotPath): + """Boxen Plot of the number of samples received by all nodes""" + plt.clf() + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "Number of Samples Received by Nodes" + conf["xlabel"] = "Node Type" + conf["ylabel"] = "Number of Samples Received" + n1 = int(result.numberNodes * result.class1ratio) + data = [result.sampleRecvCount[1: n1], result.sampleRecvCount[n1: ]] + plt.figure(figsize=(8, 6)) + sns.boxenplot(data=data, width=0.8) + plt.xlabel(conf["xlabel"]) + plt.ylabel(conf["ylabel"]) + plt.title(conf["title"]) + plt.tight_layout() + plt.savefig(plotPath + "/boxen_samplesRecv.png") + plt.close() + print("Plot %s created." % (plotPath + "/boxen_samplesRecv.png")) + + def plotBoxenSamplesRepaired(self, result, plotPath): + """Boxen Plot of the number of samples repaired by all nodes""" + plt.clf() + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "Number of Samples Repaired by Nodes" + conf["xlabel"] = "Node Type" + conf["ylabel"] = "Number of Samples Repaired" + n1 = int(result.numberNodes * result.class1ratio) + data = [result.repairedSampleCount[1: n1], result.repairedSampleCount[n1: ]] + plt.figure(figsize=(8, 6)) + sns.boxenplot(data=data, width=0.8) + plt.xlabel(conf["xlabel"]) + plt.ylabel(conf["ylabel"]) + plt.title(conf["title"]) + plt.tight_layout() + plt.savefig(plotPath + "/boxen_samplesRepaired.png") + plt.close() + print("Plot %s created." % (plotPath + "/boxen_samplesRepaired.png")) + + def plotBoxenRowColDist(self, result, plotPath): + """Boxen Plot of the Row/Column distribution""" + plt.clf() + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "Row/Column Distribution" + conf["xlabel"] = "Row/Column Type" + conf["ylabel"] = "Validators Subscribed" + vector1 = result.metrics["rowDist"] + vector2 = result.metrics["columnDist"] + if len(vector1) > len(vector2): + vector2 += [np.nan] * (len(vector1) - len(vector2)) + elif len(vector1) < len(vector2): + vector1 += [np.nan] * (len(vector2) - len(vector1)) + data = [vector1, vector2] + plt.figure(figsize=(8, 6)) + sns.boxenplot(data=data, width=0.8) + plt.xlabel(conf["xlabel"]) + plt.ylabel(conf["ylabel"]) + plt.title(conf["title"]) + plt.tight_layout() + plt.savefig(plotPath + "/boxen_rowColDist.png") + plt.close() + print("Plot %s created." % (plotPath + "/boxen_rowColDist.png")) + + def plotBoxenMessagesSent(self, result, plotPath): + """Plots the number of messages sent by all nodes using seaborn's boxenplot""" + plt.clf() + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "Number of Messages Sent by Nodes" + conf["xlabel"] = "Node Type" + conf["ylabel"] = "Number of Messages Sent" + n1 = int(result.numberNodes * result.class1ratio) + data = [result.msgSentCount[1: n1], result.msgSentCount[n1: ]] + labels = ["Class 1", "Class 2"] + sns.boxenplot(data=data, palette="Set2", ax=plt.gca()) + plt.xlabel(conf["xlabel"]) + plt.ylabel(conf["ylabel"]) + plt.title(conf["title"]) + plt.savefig(plotPath + "/boxen_messagesSent.png", bbox_inches="tight") + print("Plot %s created." % (plotPath + "/boxen_messagesSent.png")) + + def plotBoxenMessagesRecv(self, result, plotPath): + """Plots the number of messages received by all nodes using seaborn's boxenplot""" + plt.clf() + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "Number of Messages Received by Nodes" + conf["xlabel"] = "Node Type" + conf["ylabel"] = "Number of Messages Received" + n1 = int(result.numberNodes * result.class1ratio) + data = [result.msgRecvCount[1: n1], result.msgRecvCount[n1: ]] + labels = ["Class 1", "Class 2"] + sns.boxenplot(data=data, palette="Set2", ax=plt.gca()) + plt.xlabel(conf["xlabel"]) + plt.ylabel(conf["ylabel"]) + plt.title(conf["title"]) + plt.savefig(plotPath + "/boxen_messagesRecv.png", bbox_inches="tight") + print("Plot %s created." % (plotPath + "/boxen_messagesRecv.png")) + + def plotBoxSamplesRepaired(self, result, plotPath): + """Box Plot of the number of samples repaired by all nodes""" + plt.clf() + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "Number of Samples Repaired by Nodes" + conf["type"] = "individual_bar" + conf["legLoc"] = 1 + conf["desLoc"] = 1 + conf["xlabel"] = "Node Type" + conf["ylabel"] = "Number of Samples Repaired" + n1 = int(result.numberNodes * result.class1ratio) + conf["data"] = [result.repairedSampleCount[1: n1], result.repairedSampleCount[n1: ]] + conf["path"] = plotPath + "/box_samplesRepaired.png" + plotBoxData(conf) + print("Plot %s created." % conf["path"]) + + def plotBoxRowCol(self, result, plotPath): + """Box Plot of the Row/Column distribution""" + plt.clf() + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "Row/Column Distribution" + conf["xlabel"] = "" + conf["ylabel"] = "Validators Subscribed" + vector1 = result.metrics["rowDist"] + vector2 = result.metrics["columnDist"] + if len(vector1) > len(vector2): + vector2 += [np.nan] * (len(vector1) - len(vector2)) + elif len(vector1) < len(vector2): + vector1 += [np.nan] * (len(vector2) - len(vector1)) + n1 = int(result.numberNodes * result.class1ratio) + conf["data"] = [vector1, vector2] + conf["path"] = plotPath + "/box_rowColDist.png" + plotBoxData(conf) + print("Plot %s created." % conf["path"]) + def plotRestoreRowCount(self, result, plotPath): """Plots the restoreRowCount for each node""" conf = {} diff --git a/smallConf.py b/smallConf.py index e4c91aa..3348a14 100644 --- a/smallConf.py +++ b/smallConf.py @@ -41,33 +41,33 @@ logLevel = logging.INFO numJobs = -1 # Number of simulation runs with the same parameters for statistical relevance -runs = [1] +runs = range(3) # Number of validators -numberNodes = [1024] +numberNodes = range(128, 513, 128) # select failure model between: "random, sequential, MEP, MEP+1, DEP, DEP+1, MREP, MREP-1" failureModels = ["random"] # Percentage of block not released by producer -failureRates = [0] +failureRates = range(40, 81, 20) # Percentage of nodes that are considered malicious -maliciousNodes = [0] +maliciousNodes = range(40,41,20) # Parameter to determine whether to randomly assign malicious nodes or not # If True, the malicious nodes will be assigned randomly; if False, a predefined pattern may be used randomizeMaliciousNodes = True # Per-topic mesh neighborhood size -netDegrees = [8] +netDegrees = range(8, 9, 2) # ratio of class1 nodes (see below for parameters per class) class1ratios = [0.8] # Number of validators per beacon node -validatorsPerNode1 = [1] -validatorsPerNode2 = [1] +validatorsPerNode1 = [10] +validatorsPerNode2 = [50] # Set uplink bandwidth in megabits/second bwUplinksProd = [200] @@ -98,12 +98,12 @@ diagnostics = False # True to save git diff and git commit saveGit = False -blockSizeR = [128] -blockSizeC = [64] -blockSizeRK = [64] -blockSizeCK = [64] -chiR = [2] -chiC = [2] +blockSizeR = range(64, 113, 128) +blockSizeC = range(32, 113, 128) +blockSizeRK = range(32, 65, 128) +blockSizeCK = range(32, 65, 128) +chiR = range(2, 3, 2) +chiC = range(2, 3, 2) def nextShape(): for blckSizeR, blckSizeRK, blckSizeC, blckSizeCK, run, fm, fr, mn, class1ratio, chR, chC, vpn1, vpn2, nn, netDegree, bwUplinkProd, bwUplink1, bwUplink2 in itertools.product( From 14dc9543d7071abfae16c91c20e5d14879862aaa Mon Sep 17 00:00:00 2001 From: Arunima Chaudhuri Date: Thu, 29 Feb 2024 20:09:46 +0100 Subject: [PATCH 15/21] correcting class ration in graphs Signed-off-by: Arunima Chaudhuri --- DAS/visualizor.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/DAS/visualizor.py b/DAS/visualizor.py index 0bd1721..973cd72 100644 --- a/DAS/visualizor.py +++ b/DAS/visualizor.py @@ -219,9 +219,6 @@ class Visualizor: plt.xlim(left=0, right=max(result.repairedSampleCount) * 1.1) plt.savefig(plotPath + "/ecdf_samplesRepaired.png", bbox_inches="tight") print("Plot %s created." % (plotPath + "/ecdf_samplesRepaired.png")) - - - def plotBoxenSamplesRecv(self, result, plotPath): """Boxen Plot of the number of samples received by all nodes""" @@ -234,7 +231,7 @@ class Visualizor: conf["xlabel"] = "Node Type" conf["ylabel"] = "Number of Samples Received" n1 = int(result.numberNodes * result.class1ratio) - data = [result.sampleRecvCount[1: n1], result.sampleRecvCount[n1: ]] + data = [result.sampleRecvCount[1: n1], result.sampleRecvCount[n1+1: ]] plt.figure(figsize=(8, 6)) sns.boxenplot(data=data, width=0.8) plt.xlabel(conf["xlabel"]) @@ -256,7 +253,7 @@ class Visualizor: conf["xlabel"] = "Node Type" conf["ylabel"] = "Number of Samples Repaired" n1 = int(result.numberNodes * result.class1ratio) - data = [result.repairedSampleCount[1: n1], result.repairedSampleCount[n1: ]] + data = [result.repairedSampleCount[1: n1], result.repairedSampleCount[n1+1: ]] plt.figure(figsize=(8, 6)) sns.boxenplot(data=data, width=0.8) plt.xlabel(conf["xlabel"]) @@ -305,7 +302,7 @@ class Visualizor: conf["xlabel"] = "Node Type" conf["ylabel"] = "Number of Messages Sent" n1 = int(result.numberNodes * result.class1ratio) - data = [result.msgSentCount[1: n1], result.msgSentCount[n1: ]] + data = [result.msgSentCount[1: n1], result.msgSentCount[n1+1: ]] labels = ["Class 1", "Class 2"] sns.boxenplot(data=data, palette="Set2", ax=plt.gca()) plt.xlabel(conf["xlabel"]) @@ -325,7 +322,7 @@ class Visualizor: conf["xlabel"] = "Node Type" conf["ylabel"] = "Number of Messages Received" n1 = int(result.numberNodes * result.class1ratio) - data = [result.msgRecvCount[1: n1], result.msgRecvCount[n1: ]] + data = [result.msgRecvCount[1: n1], result.msgRecvCount[n1+1: ]] labels = ["Class 1", "Class 2"] sns.boxenplot(data=data, palette="Set2", ax=plt.gca()) plt.xlabel(conf["xlabel"]) @@ -348,7 +345,7 @@ class Visualizor: conf["xlabel"] = "Node Type" conf["ylabel"] = "Number of Samples Repaired" n1 = int(result.numberNodes * result.class1ratio) - conf["data"] = [result.repairedSampleCount[1: n1], result.repairedSampleCount[n1: ]] + conf["data"] = [result.repairedSampleCount[1: n1], result.repairedSampleCount[n1+1: ]] conf["path"] = plotPath + "/box_samplesRepaired.png" plotBoxData(conf) print("Plot %s created." % conf["path"]) @@ -461,7 +458,7 @@ class Visualizor: conf["xlabel"] = "Node Type" conf["ylabel"] = "Number of samples received (%)" n1 = int(result.numberNodes * result.class1ratio) - conf["data"] = [result.sampleRecvCount[1: n1], result.sampleRecvCount[n1: ]] + conf["data"] = [result.sampleRecvCount[1: n1], result.sampleRecvCount[n1+1: ]] conf["xdots"] = range(result.shape.numberNodes) conf["path"] = plotPath + "/box_sampleRecv.png" plotBoxData(conf) @@ -676,7 +673,7 @@ class Visualizor: conf["xlabel"] = "Node Type" conf["ylabel"] = "Number of Messages Sent" n1 = int(result.numberNodes * result.class1ratio) - conf["data"] = [result.msgSentCount[1: n1], result.msgSentCount[n1: ]] + conf["data"] = [result.msgSentCount[1: n1], result.msgSentCount[n1+1: ]] conf["path"] = plotPath + "/box_messagesSent.png" plotBoxData(conf) print("Plot %s created." % conf["path"]) @@ -714,7 +711,7 @@ class Visualizor: conf["xlabel"] = "Node Type" conf["ylabel"] = "Number of Messages Received" n1 = int(result.numberNodes * result.class1ratio) - conf["data"] = [result.msgRecvCount[1: n1], result.msgRecvCount[n1: ]] + conf["data"] = [result.msgRecvCount[1: n1], result.msgRecvCount[n1+1: ]] conf["xdots"] = range(result.shape.numberNodes) conf["path"] = plotPath + "/box_messagesRecv.png" maxi = max(conf["data"]) From bf064e40f306618becf34e4bc10f91073fe423e1 Mon Sep 17 00:00:00 2001 From: Arunima Chaudhuri Date: Fri, 1 Mar 2024 19:55:21 +0100 Subject: [PATCH 16/21] Updated ECDF plots to plot data classwise Signed-off-by: Arunima Chaudhuri --- DAS/visualizor.py | 57 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/DAS/visualizor.py b/DAS/visualizor.py index 973cd72..025fc21 100644 --- a/DAS/visualizor.py +++ b/DAS/visualizor.py @@ -112,7 +112,6 @@ class Visualizor: self.plotBoxenSamplesRecv(result, plotPath) self.plotBoxenSamplesRepaired(result, plotPath) self.plotBoxenRowColDist(result, plotPath) - self.plotECDFSamplesRepaired(result, plotPath) self.plotECDFRowColDist(result, plotPath) self.plotECDFSamplesReceived(result, plotPath) @@ -132,11 +131,18 @@ class Visualizor: conf["title"] = "ECDF of Messages Sent by Nodes" conf["xlabel"] = "Number of Messages Sent" conf["ylabel"] = "ECDF" - sns.ecdfplot(data=result.msgSentCount) + n1 = int(result.numberNodes * result.class1ratio) + class1_data = result.msgSentCount[1: n1] + class2_data = result.msgSentCount[n1+1: ] + sns.ecdfplot(data=class1_data, label='Class 1 Nodes') + sns.ecdfplot(data=class2_data, label='Class 2 Nodes') + plt.legend(title='Node Class', labels=['Class 1 Nodes', 'Class 2 Nodes'], loc=1) plt.xlabel(conf["xlabel"]) plt.ylabel(conf["ylabel"]) plt.title(conf["title"]) plt.xlim(left=0, right=max(result.msgSentCount) * 1.1) + props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) + plt.text(0.05, 0.05, conf["textBox"], fontsize=10, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props) plt.savefig(plotPath + "/ecdf_messagesSent.png", bbox_inches="tight") print("Plot %s created." % (plotPath + "/ecdf_messagesSent.png")) @@ -150,11 +156,18 @@ class Visualizor: conf["title"] = "ECDF of Messages Received by Nodes" conf["xlabel"] = "Number of Messages Received" conf["ylabel"] = "ECDF" - sns.ecdfplot(data=result.msgRecvCount) + n1 = int(result.numberNodes * result.class1ratio) + class1_data = result.msgRecvCount[1: n1] + class2_data = result.msgRecvCount[n1+1: ] + sns.ecdfplot(data=class1_data, label='Class 1 Nodes') + sns.ecdfplot(data=class2_data, label='Class 2 Nodes') + plt.legend(title='Node Class', labels=['Class 1 Nodes', 'Class 2 Nodes'], loc=1) plt.xlabel(conf["xlabel"]) plt.ylabel(conf["ylabel"]) plt.title(conf["title"]) plt.xlim(left=0, right=max(result.msgRecvCount) * 1.1) + props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) + plt.text(0.05, 0.05, conf["textBox"], fontsize=10, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props) plt.savefig(plotPath + "/ecdf_messagesRecv.png", bbox_inches="tight") print("Plot %s created." % (plotPath + "/ecdf_messagesRecv.png")) @@ -168,11 +181,18 @@ class Visualizor: conf["title"] = "ECDF of Samples Received by Nodes" conf["xlabel"] = "Number of Samples Received" conf["ylabel"] = "ECDF" - sns.ecdfplot(data=result.sampleRecvCount) + n1 = int(result.numberNodes * result.class1ratio) + class1_data = result.sampleRecvCount[1: n1] + class2_data = result.sampleRecvCount[n1+1: ] + sns.ecdfplot(data=class1_data, label='Class 1 Nodes') + sns.ecdfplot(data=class2_data, label='Class 2 Nodes') + plt.legend(title='Node Class', labels=['Class 1 Nodes', 'Class 2 Nodes'], loc=1) plt.xlabel(conf["xlabel"]) plt.ylabel(conf["ylabel"]) plt.title(conf["title"]) plt.xlim(left=0, right=max(result.sampleRecvCount) * 1.1) + props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) + plt.text(0.05, 0.05, conf["textBox"], fontsize=10, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props) plt.savefig(plotPath + "/ecdf_samplesReceived.png", bbox_inches="tight") print("Plot %s created." % (plotPath + "/ecdf_samplesReceived.png")) @@ -188,17 +208,17 @@ class Visualizor: conf["ylabel"] = "ECDF" vector1 = result.metrics["rowDist"] vector2 = result.metrics["columnDist"] - if len(vector1) > len(vector2): - vector2 += [np.nan] * (len(vector1) - len(vector2)) - elif len(vector1) < len(vector2): - vector1 += [np.nan] * (len(vector2) - len(vector1)) n1 = int(result.numberNodes * result.class1ratio) conf["data"] = [vector1, vector2] - sns.ecdfplot(data=conf["data"]) + sns.ecdfplot(data=vector1, label='Rows') + sns.ecdfplot(data=vector2, label='Columns') plt.xlabel(conf["xlabel"]) plt.ylabel(conf["ylabel"]) plt.title(conf["title"]) plt.xlim(left=0, right=max(max(vector1), max(vector2)) * 1.1) + plt.legend(labels=['Row Dist', 'Column Dist'], loc=1) + props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) + plt.text(0.05, 0.05, conf["textBox"], fontsize=10, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props) plt.savefig(plotPath + "/ecdf_rowColDist.png", bbox_inches="tight") print("Plot %s created." % (plotPath + "/ecdf_rowColDist.png")) @@ -212,11 +232,18 @@ class Visualizor: conf["title"] = "ECDF of Samples Repaired by Nodes" conf["xlabel"] = "Number of Samples Repaired" conf["ylabel"] = "ECDF" - sns.ecdfplot(data=result.repairedSampleCount) + n1 = int(result.numberNodes * result.class1ratio) + class1_data = result.repairedSampleCount[1: n1] + class2_data = result.repairedSampleCount[n1+1: ] + sns.ecdfplot(data=class1_data, label='Class 1 Nodes') + sns.ecdfplot(data=class2_data, label='Class 2 Nodes') + plt.legend(title='Node Class', labels=['Class 1 Nodes', 'Class 2 Nodes']) plt.xlabel(conf["xlabel"]) plt.ylabel(conf["ylabel"]) plt.title(conf["title"]) plt.xlim(left=0, right=max(result.repairedSampleCount) * 1.1) + props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) + plt.text(0.05, 0.05, conf["textBox"], fontsize=10, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props) plt.savefig(plotPath + "/ecdf_samplesRepaired.png", bbox_inches="tight") print("Plot %s created." % (plotPath + "/ecdf_samplesRepaired.png")) @@ -237,6 +264,8 @@ class Visualizor: plt.xlabel(conf["xlabel"]) plt.ylabel(conf["ylabel"]) plt.title(conf["title"]) + props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) + plt.text(0.05, 0.05, conf["textBox"], fontsize=10, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props) plt.tight_layout() plt.savefig(plotPath + "/boxen_samplesRecv.png") plt.close() @@ -259,6 +288,8 @@ class Visualizor: plt.xlabel(conf["xlabel"]) plt.ylabel(conf["ylabel"]) plt.title(conf["title"]) + props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) + plt.text(0.05, 0.05, conf["textBox"], fontsize=10, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props) plt.tight_layout() plt.savefig(plotPath + "/boxen_samplesRepaired.png") plt.close() @@ -286,6 +317,8 @@ class Visualizor: plt.xlabel(conf["xlabel"]) plt.ylabel(conf["ylabel"]) plt.title(conf["title"]) + props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) + plt.text(0.05, 0.05, conf["textBox"], fontsize=10, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props) plt.tight_layout() plt.savefig(plotPath + "/boxen_rowColDist.png") plt.close() @@ -308,6 +341,8 @@ class Visualizor: plt.xlabel(conf["xlabel"]) plt.ylabel(conf["ylabel"]) plt.title(conf["title"]) + props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) + plt.text(0.05, 0.05, conf["textBox"], fontsize=10, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props) plt.savefig(plotPath + "/boxen_messagesSent.png", bbox_inches="tight") print("Plot %s created." % (plotPath + "/boxen_messagesSent.png")) @@ -328,6 +363,8 @@ class Visualizor: plt.xlabel(conf["xlabel"]) plt.ylabel(conf["ylabel"]) plt.title(conf["title"]) + props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) + plt.text(0.05, 0.05, conf["textBox"], fontsize=10, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props) plt.savefig(plotPath + "/boxen_messagesRecv.png", bbox_inches="tight") print("Plot %s created." % (plotPath + "/boxen_messagesRecv.png")) From 1893cc7bd0e2f89df8a6e3941605bc0e44457d60 Mon Sep 17 00:00:00 2001 From: Arunima Chaudhuri Date: Fri, 1 Mar 2024 20:11:49 +0100 Subject: [PATCH 17/21] comment out bar plots & box plots Signed-off-by: Arunima Chaudhuri --- DAS/visualizor.py | 50 ++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/DAS/visualizor.py b/DAS/visualizor.py index 025fc21..51634ea 100644 --- a/DAS/visualizor.py +++ b/DAS/visualizor.py @@ -91,34 +91,41 @@ class Visualizor: for result in self.results: plotPath = "results/"+self.execID+"/plots/"+str(result.shape) os.makedirs(plotPath, exist_ok=True) - self.plotRestoreRowCount(result, plotPath) - self.plotRestoreColumnCount(result, plotPath) - self.plotMessagesSent(result, plotPath) - self.plotBoxMessagesSent(result, plotPath) - self.plotMessagesRecv(result, plotPath) - self.plotBoxMessagesRecv(result, plotPath) - self.plotSampleRecv(result, plotPath) - self.plotBoxSampleRecv(result, plotPath) self.plotMissingSamples(result, plotPath) self.plotProgress(result, plotPath) self.plotSentData(result, plotPath) self.plotRecvData(result, plotPath) self.plotDupData(result, plotPath) - self.plotSamplesRepaired(result, plotPath) - self.plotBoxSamplesRepaired(result, plotPath) - self.plotBoxRowCol(result, plotPath) - self.plotBoxenMessagesRecv(result, plotPath) - self.plotBoxenMessagesSent(result, plotPath) - self.plotBoxenSamplesRecv(result, plotPath) + self.plotRestoreRowCount(result, plotPath) + self.plotRestoreColumnCount(result, plotPath) + + # self.plotSamplesRepaired(result, plotPath) + # self.plotMessagesSent(result, plotPath) + # self.plotMessagesRecv(result, plotPath) + # self.plotSampleRecv(result, plotPath) + # if self.config.saveRCdist: + # self.plotRowCol(result, plotPath) + + # self.plotBoxSamplesRepaired(result, plotPath) + # self.plotBoxMessagesSent(result, plotPath) + # self.plotBoxMessagesRecv(result, plotPath) + # self.plotBoxSampleRecv(result, plotPath) + # if self.config.saveRCdist: + # self.plotBoxRowCol(result, plotPath) + self.plotBoxenSamplesRepaired(result, plotPath) - self.plotBoxenRowColDist(result, plotPath) - self.plotECDFSamplesRepaired(result, plotPath) - self.plotECDFRowColDist(result, plotPath) - self.plotECDFSamplesReceived(result, plotPath) - self.plotECDFMessagesRecv(result, plotPath) - self.plotECDFMessagesSent(result, plotPath) + self.plotBoxenMessagesSent(result, plotPath) + self.plotBoxenMessagesRecv(result, plotPath) + self.plotBoxenSamplesRecv(result, plotPath) if self.config.saveRCdist: - self.plotRowCol(result, plotPath) + self.plotBoxenRowColDist(result, plotPath) + + self.plotECDFSamplesRepaired(result, plotPath) + self.plotECDFMessagesSent(result, plotPath) + self.plotECDFMessagesRecv(result, plotPath) + self.plotECDFSamplesReceived(result, plotPath) + if self.config.saveRCdist: + self.plotECDFRowColDist(result, plotPath) def plotECDFMessagesSent(self, result, plotPath): @@ -209,7 +216,6 @@ class Visualizor: vector1 = result.metrics["rowDist"] vector2 = result.metrics["columnDist"] n1 = int(result.numberNodes * result.class1ratio) - conf["data"] = [vector1, vector2] sns.ecdfplot(data=vector1, label='Rows') sns.ecdfplot(data=vector2, label='Columns') plt.xlabel(conf["xlabel"]) From 62a2116434bcf74b0779aca5169fa79548ca75e9 Mon Sep 17 00:00:00 2001 From: Arunima Chaudhuri Date: Sat, 2 Mar 2024 13:05:24 +0000 Subject: [PATCH 18/21] add ecdf, boxen, box plots for restore row & col Signed-off-by: Arunima Chaudhuri --- DAS/visualizor.py | 148 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 146 insertions(+), 2 deletions(-) diff --git a/DAS/visualizor.py b/DAS/visualizor.py index 51634ea..799e203 100644 --- a/DAS/visualizor.py +++ b/DAS/visualizor.py @@ -96,13 +96,13 @@ class Visualizor: self.plotSentData(result, plotPath) self.plotRecvData(result, plotPath) self.plotDupData(result, plotPath) - self.plotRestoreRowCount(result, plotPath) - self.plotRestoreColumnCount(result, plotPath) # self.plotSamplesRepaired(result, plotPath) # self.plotMessagesSent(result, plotPath) # self.plotMessagesRecv(result, plotPath) # self.plotSampleRecv(result, plotPath) + # self.plotRestoreRowCount(result, plotPath) + # self.plotRestoreColumnCount(result, plotPath) # if self.config.saveRCdist: # self.plotRowCol(result, plotPath) @@ -110,6 +110,8 @@ class Visualizor: # self.plotBoxMessagesSent(result, plotPath) # self.plotBoxMessagesRecv(result, plotPath) # self.plotBoxSampleRecv(result, plotPath) + # self.plotBoxRestoreColumnCount(result, plotPath) + # self.plotBoxRestoreRowCount(result, plotPath) # if self.config.saveRCdist: # self.plotBoxRowCol(result, plotPath) @@ -117,6 +119,8 @@ class Visualizor: self.plotBoxenMessagesSent(result, plotPath) self.plotBoxenMessagesRecv(result, plotPath) self.plotBoxenSamplesRecv(result, plotPath) + self.plotBoxenRestoreRowCount(result, plotPath) + self.plotBoxenRestoreColumnCount(result, plotPath) if self.config.saveRCdist: self.plotBoxenRowColDist(result, plotPath) @@ -124,10 +128,150 @@ class Visualizor: self.plotECDFMessagesSent(result, plotPath) self.plotECDFMessagesRecv(result, plotPath) self.plotECDFSamplesReceived(result, plotPath) + self.plotECDFRestoreRowCount(result, plotPath) + self.plotECDFRestoreColumnCount(result, plotPath) if self.config.saveRCdist: self.plotECDFRowColDist(result, plotPath) + def plotBoxRestoreRowCount(self, result, plotPath): + """Box Plot of restoreRowCount for all nodes""" + plt.clf() + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "Box Plot of Restore Row Count by Nodes" + conf["xlabel"] = "Node Type" + conf["ylabel"] = "Restore Row Count" + n1 = int(result.numberNodes * result.class1ratio) + class1_data = result.restoreRowCount[1: n1] + class2_data = result.restoreRowCount[n1+1: ] + data = [class1_data, class2_data] + plt.boxplot(data) + plt.xticks([1, 2], ['Class 1 Nodes', 'Class 2 Nodes']) + plt.xlabel(conf["xlabel"]) + plt.ylabel(conf["ylabel"]) + plt.title(conf["title"]) + plt.savefig(plotPath + "/box_restoreRowCount.png", bbox_inches="tight") + print("Plot %s created." % (plotPath + "/box_restoreRowCount.png")) + + def plotBoxRestoreColumnCount(self, result, plotPath): + """Box Plot of restoreColumnCount for all nodes""" + plt.clf() + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "Box Plot of Restore Column Count by Nodes" + conf["xlabel"] = "Node Type" + conf["ylabel"] = "Restore Column Count" + n1 = int(result.numberNodes * result.class1ratio) + class1_data = result.restoreColumnCount[1: n1] + class2_data = result.restoreColumnCount[n1+1: ] + data = [class1_data, class2_data] + plt.boxplot(data) + plt.xticks([1, 2], ['Class 1 Nodes', 'Class 2 Nodes']) + plt.xlabel(conf["xlabel"]) + plt.ylabel(conf["ylabel"]) + plt.title(conf["title"]) + plt.savefig(plotPath + "/box_restoreColumnCount.png", bbox_inches="tight") + print("Plot %s created." % (plotPath + "/box_restoreColumnCount.png")) + + def plotBoxenRestoreRowCount(self, result, plotPath): + """Plots the Boxen plot of restoreRowCount for all nodes""" + plt.clf() + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "Boxen Plot of Restore Row Count by Nodes" + conf["xlabel"] = "Restore Row Count" + conf["ylabel"] = "Nodes" + n1 = int(result.numberNodes * result.class1ratio) + data = [result.restoreRowCount[1: n1], result.restoreRowCount[n1+1: ]] + plt.figure(figsize=(8, 6)) + sns.boxenplot(data=data, width=0.8) + plt.xlabel(conf["xlabel"]) + plt.ylabel(conf["ylabel"]) + plt.title(conf["title"]) + props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) + plt.text(0.05, 0.05, conf["textBox"], fontsize=10, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props) + plt.savefig(plotPath + "/boxen_restoreRowCount.png", bbox_inches="tight") + print("Plot %s created." % (plotPath + "/boxen_restoreRowCount.png")) + + def plotBoxenRestoreColumnCount(self, result, plotPath): + """Plots the Boxen plot of restoreColumnCount for all nodes""" + plt.clf() + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "Boxen Plot of Restore Column Count by Nodes" + conf["xlabel"] = "Restore Column Count" + conf["ylabel"] = "Nodes" + n1 = int(result.numberNodes * result.class1ratio) + data = [result.restoreColumnCount[1: n1], result.restoreColumnCount[n1+1: ]] + plt.figure(figsize=(8, 6)) + sns.boxenplot(data=data, width=0.8) + plt.xlabel(conf["xlabel"]) + plt.ylabel(conf["ylabel"]) + plt.title(conf["title"]) + props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) + plt.text(0.05, 0.05, conf["textBox"], fontsize=10, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props) + plt.savefig(plotPath + "/boxen_restoreColumnCount.png", bbox_inches="tight") + print("Plot %s created." % (plotPath + "/boxen_restoreColumnCount.png")) + + def plotECDFRestoreRowCount(self, result, plotPath): + """Plots the ECDF of restoreRowCount for all nodes using seaborn's ecdfplot""" + plt.clf() + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "ECDF of Restore Row Count by Nodes" + conf["xlabel"] = "Restore Row Count" + conf["ylabel"] = "ECDF" + n1 = int(result.numberNodes * result.class1ratio) + class1_data = result.restoreRowCount[1: n1] + class2_data = result.restoreRowCount[n1+1: ] + sns.ecdfplot(data=class1_data, label='Class 1 Nodes') + sns.ecdfplot(data=class2_data, label='Class 2 Nodes') + plt.xlabel(conf["xlabel"]) + plt.ylabel(conf["ylabel"]) + plt.title(conf["title"]) + plt.xlim(left=0, right=max(result.restoreRowCount) * 1.1) + props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) + plt.text(0.05, 0.05, conf["textBox"], fontsize=10, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props) + plt.legend(title='Node Class', labels=['Class 1 Nodes', 'Class 2 Nodes'], loc=1) + plt.savefig(plotPath + "/ecdf_restoreRowCount.png", bbox_inches="tight") + print("Plot %s created." % (plotPath + "/ecdf_restoreRowCount.png")) + + def plotECDFRestoreColumnCount(self, result, plotPath): + """Plots the ECDF of restoreColumnCount for all nodes using seaborn's ecdfplot""" + plt.clf() + conf = {} + text = str(result.shape).split("-") + conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ + +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + conf["title"] = "ECDF of Restore Column Count by Nodes" + conf["xlabel"] = "Restore Column Count" + conf["ylabel"] = "ECDF" + n1 = int(result.numberNodes * result.class1ratio) + class1_data = result.restoreColumnCount[1: n1] + class2_data = result.restoreColumnCount[n1+1: ] + sns.ecdfplot(data=class1_data, label='Class 1 Nodes') + sns.ecdfplot(data=class2_data, label='Class 2 Nodes') + plt.xlabel(conf["xlabel"]) + plt.ylabel(conf["ylabel"]) + plt.title(conf["title"]) + plt.xlim(left=0, right=max(result.restoreColumnCount) * 1.1) + props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) + plt.text(0.05, 0.05, conf["textBox"], fontsize=10, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props) + plt.legend(title='Node Class', labels=['Class 1 Nodes', 'Class 2 Nodes'], loc=1) + plt.savefig(plotPath + "/ecdf_restoreColumnCount.png", bbox_inches="tight") + print("Plot %s created." % (plotPath + "/ecdf_restoreColumnCount.png")) + def plotECDFMessagesSent(self, result, plotPath): """Plots the ECDF of messages sent by all nodes using seaborn's ecdfplot""" plt.clf() From 08883e560f990b0a024b8a2112c5bda67c8922d5 Mon Sep 17 00:00:00 2001 From: Arunima Chaudhuri Date: Sat, 2 Mar 2024 13:10:25 +0000 Subject: [PATCH 19/21] add plt.text Signed-off-by: Arunima Chaudhuri --- DAS/visualizor.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DAS/visualizor.py b/DAS/visualizor.py index 799e203..85a7b4e 100644 --- a/DAS/visualizor.py +++ b/DAS/visualizor.py @@ -153,6 +153,8 @@ class Visualizor: plt.xlabel(conf["xlabel"]) plt.ylabel(conf["ylabel"]) plt.title(conf["title"]) + props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) + plt.text(0.05, 0.05, conf["textBox"], fontsize=10, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props) plt.savefig(plotPath + "/box_restoreRowCount.png", bbox_inches="tight") print("Plot %s created." % (plotPath + "/box_restoreRowCount.png")) @@ -175,6 +177,8 @@ class Visualizor: plt.xlabel(conf["xlabel"]) plt.ylabel(conf["ylabel"]) plt.title(conf["title"]) + props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) + plt.text(0.05, 0.05, conf["textBox"], fontsize=10, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props) plt.savefig(plotPath + "/box_restoreColumnCount.png", bbox_inches="tight") print("Plot %s created." % (plotPath + "/box_restoreColumnCount.png")) From d92468b69b82aafe244be5d7cb145a8271f5464e Mon Sep 17 00:00:00 2001 From: Arunima Chaudhuri Date: Sun, 3 Mar 2024 02:25:07 +0530 Subject: [PATCH 20/21] correct index Signed-off-by: Arunima Chaudhuri --- DAS/visualizor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DAS/visualizor.py b/DAS/visualizor.py index 2f250a3..dcca2a3 100644 --- a/DAS/visualizor.py +++ b/DAS/visualizor.py @@ -63,7 +63,7 @@ class Visualizor: def __get_attrbs__(self, result): text = str(result.shape).split("-") d = dict() - for i in range(0, len(text), 2): + for i in range(1, len(text), 2): d[text[i]] = text[i + 1] return d From 2add749fb5acda8c9aec4bfac37511536d47b35c Mon Sep 17 00:00:00 2001 From: Arunima Chaudhuri Date: Sun, 3 Mar 2024 18:34:16 +0530 Subject: [PATCH 21/21] clean code of graphs Signed-off-by: Arunima Chaudhuri --- DAS/visualizor.py | 178 +++++++++++++++++++++++----------------------- 1 file changed, 89 insertions(+), 89 deletions(-) diff --git a/DAS/visualizor.py b/DAS/visualizor.py index dcca2a3..b57cfd7 100644 --- a/DAS/visualizor.py +++ b/DAS/visualizor.py @@ -171,9 +171,9 @@ class Visualizor: """Box Plot of restoreRowCount for all nodes""" plt.clf() conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Box Plot of Restore Row Count by Nodes" conf["xlabel"] = "Node Type" conf["ylabel"] = "Restore Row Count" @@ -195,9 +195,9 @@ class Visualizor: """Box Plot of restoreColumnCount for all nodes""" plt.clf() conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Box Plot of Restore Column Count by Nodes" conf["xlabel"] = "Node Type" conf["ylabel"] = "Restore Column Count" @@ -219,9 +219,9 @@ class Visualizor: """Plots the Boxen plot of restoreRowCount for all nodes""" plt.clf() conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Boxen Plot of Restore Row Count by Nodes" conf["xlabel"] = "Restore Row Count" conf["ylabel"] = "Nodes" @@ -241,9 +241,9 @@ class Visualizor: """Plots the Boxen plot of restoreColumnCount for all nodes""" plt.clf() conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Boxen Plot of Restore Column Count by Nodes" conf["xlabel"] = "Restore Column Count" conf["ylabel"] = "Nodes" @@ -263,9 +263,9 @@ class Visualizor: """Plots the ECDF of restoreRowCount for all nodes using seaborn's ecdfplot""" plt.clf() conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "ECDF of Restore Row Count by Nodes" conf["xlabel"] = "Restore Row Count" conf["ylabel"] = "ECDF" @@ -288,9 +288,9 @@ class Visualizor: """Plots the ECDF of restoreColumnCount for all nodes using seaborn's ecdfplot""" plt.clf() conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "ECDF of Restore Column Count by Nodes" conf["xlabel"] = "Restore Column Count" conf["ylabel"] = "ECDF" @@ -313,9 +313,9 @@ class Visualizor: """Plots the ECDF of messages sent by all nodes using seaborn's ecdfplot""" plt.clf() conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "ECDF of Messages Sent by Nodes" conf["xlabel"] = "Number of Messages Sent" conf["ylabel"] = "ECDF" @@ -338,9 +338,9 @@ class Visualizor: """Plots the ECDF of messages received by all nodes using seaborn's ecdfplot""" plt.clf() conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "ECDF of Messages Received by Nodes" conf["xlabel"] = "Number of Messages Received" conf["ylabel"] = "ECDF" @@ -363,9 +363,9 @@ class Visualizor: """Plots the ECDF of samples received by all nodes using seaborn's ecdfplot""" plt.clf() conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "ECDF of Samples Received by Nodes" conf["xlabel"] = "Number of Samples Received" conf["ylabel"] = "ECDF" @@ -388,9 +388,9 @@ class Visualizor: """Plots the ECDF of row col distance by all nodes using seaborn's ecdfplot""" plt.clf() conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "ECDF of Row-Col Distance by Nodes" conf["xlabel"] = "Row-Col Distance" conf["ylabel"] = "ECDF" @@ -413,9 +413,9 @@ class Visualizor: """Plots the ECDF of samples repaired by all nodes using seaborn's ecdfplot""" plt.clf() conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "ECDF of Samples Repaired by Nodes" conf["xlabel"] = "Number of Samples Repaired" conf["ylabel"] = "ECDF" @@ -438,9 +438,9 @@ class Visualizor: """Boxen Plot of the number of samples received by all nodes""" plt.clf() conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Number of Samples Received by Nodes" conf["xlabel"] = "Node Type" conf["ylabel"] = "Number of Samples Received" @@ -462,9 +462,9 @@ class Visualizor: """Boxen Plot of the number of samples repaired by all nodes""" plt.clf() conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Number of Samples Repaired by Nodes" conf["xlabel"] = "Node Type" conf["ylabel"] = "Number of Samples Repaired" @@ -486,9 +486,9 @@ class Visualizor: """Boxen Plot of the Row/Column distribution""" plt.clf() conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Row/Column Distribution" conf["xlabel"] = "Row/Column Type" conf["ylabel"] = "Validators Subscribed" @@ -515,9 +515,9 @@ class Visualizor: """Plots the number of messages sent by all nodes using seaborn's boxenplot""" plt.clf() conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Number of Messages Sent by Nodes" conf["xlabel"] = "Node Type" conf["ylabel"] = "Number of Messages Sent" @@ -537,9 +537,9 @@ class Visualizor: """Plots the number of messages received by all nodes using seaborn's boxenplot""" plt.clf() conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Number of Messages Received by Nodes" conf["xlabel"] = "Node Type" conf["ylabel"] = "Number of Messages Received" @@ -559,9 +559,9 @@ class Visualizor: """Box Plot of the number of samples repaired by all nodes""" plt.clf() conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Number of Samples Repaired by Nodes" conf["type"] = "individual_bar" conf["legLoc"] = 1 @@ -578,9 +578,9 @@ class Visualizor: """Box Plot of the Row/Column distribution""" plt.clf() conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Row/Column Distribution" conf["xlabel"] = "" conf["ylabel"] = "Validators Subscribed" @@ -599,9 +599,9 @@ class Visualizor: def plotRestoreRowCount(self, result, plotPath): """Plots the restoreRowCount for each node""" conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Restore Row Count for Each Node" conf["type"] = "individual_bar" conf["legLoc"] = 1 @@ -619,9 +619,9 @@ class Visualizor: def plotRestoreColumnCount(self, result, plotPath): """Plots the restoreColumnCount for each node""" conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Restore Column Count for Each Node" conf["type"] = "individual_bar" conf["legLoc"] = 1 @@ -639,9 +639,9 @@ class Visualizor: def plotSampleRecv(self, result, plotPath): """Plots the percentage sampleRecv for each node""" conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Percentage of Samples Received by Nodes" conf["type"] = "individual_bar_with_2line" conf["legLoc"] = 1 @@ -672,9 +672,9 @@ class Visualizor: def plotBoxSampleRecv(self, result, plotPath): """Box Plot of the sampleRecv for each node""" conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Number of Samples Received by Nodes" conf["type"] = "individual_bar_with_2line" conf["legLoc"] = 1 @@ -691,9 +691,9 @@ class Visualizor: def plotMissingSamples(self, result, plotPath): """Plots the missing samples in the network""" conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Missing Samples" conf["type"] = "plot_with_1line" conf["legLoc"] = 1 @@ -724,7 +724,7 @@ class Visualizor: conf = {} attrbs = self.__get_attrbs__(result) conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ - +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+" \nNetwork degree: "+attrbs['nd'] + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Nodes/validators ready" conf["type"] = "plot" conf["legLoc"] = 2 @@ -756,7 +756,7 @@ class Visualizor: conf = {} attrbs = self.__get_attrbs__(result) conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ - +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+" \nNetwork degree: "+attrbs['nd'] + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Sent data" conf["type"] = "plot" conf["legLoc"] = 2 @@ -786,7 +786,7 @@ class Visualizor: conf = {} attrbs = self.__get_attrbs__(result) conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ - +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+" \nNetwork degree: "+attrbs['nd'] + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Received data" conf["type"] = "plot" conf["legLoc"] = 2 @@ -816,7 +816,7 @@ class Visualizor: conf = {} attrbs = self.__get_attrbs__(result) conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ - +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+" \nNetwork degree: "+attrbs['nd'] + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Duplicated data" conf["type"] = "plot" conf["legLoc"] = 2 @@ -847,7 +847,7 @@ class Visualizor: conf = {} attrbs = self.__get_attrbs__(result) conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ - +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+" \nNetwork degree: "+attrbs['nd'] + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Row/Column distribution" conf["type"] = "grouped_bar" conf["legLoc"] = 2 @@ -870,9 +870,9 @@ class Visualizor: def plotMessagesSent(self, result, plotPath): """Plots the number of messages sent by all nodes""" conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Number of Messages Sent by Nodes" conf["type"] = "individual_bar" conf["legLoc"] = 1 @@ -890,9 +890,9 @@ class Visualizor: def plotBoxMessagesSent(self, result, plotPath): """Box Plot of the number of messages sent by all nodes""" conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+" \nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Number of Messages Sent by Nodes" conf["xlabel"] = "Node Type" conf["ylabel"] = "Number of Messages Sent" @@ -905,9 +905,9 @@ class Visualizor: def plotMessagesRecv(self, result, plotPath): """Plots the number of messages received by all nodes""" conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Number of Messages Received by Nodes" conf["type"] = "individual_bar" conf["legLoc"] = 1 @@ -925,9 +925,9 @@ class Visualizor: def plotBoxMessagesRecv(self, result, plotPath): """Plots the number of messages received by all nodes""" conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Number of Messages Received by Nodes" conf["type"] = "individual_bar" conf["legLoc"] = 1 @@ -946,9 +946,9 @@ class Visualizor: def plotSamplesRepaired(self, result, plotPath): """Plots the number of samples repaired by all nodes""" conf = {} - text = str(result.shape).split("-") - conf["textBox"] = "Row Size: "+text[2]+"\nColumn Size: "+text[6]+"\nNumber of nodes: "+text[10]\ - +"\nFailure rate: "+text[14]+"%"+"\nNetwork degree: "+text[32]+"\nMalicious Nodes: "+text[36]+"%" + attrbs = self.__get_attrbs__(result) + conf["textBox"] = "Block Size R: "+attrbs['bsrn']+"\nBlock Size C: "+attrbs['bscn']\ + +"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd'] conf["title"] = "Number of Samples Repaired by Nodes" conf["type"] = "individual_bar" conf["legLoc"] = 1