Merge pull request #54 from codex-storage/maliciousNode

Malicious node
This commit is contained in:
Arunima Chaudhuri 2024-03-03 19:09:28 +05:30 committed by GitHub
commit 169ffd8ef9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 928 additions and 136 deletions

View File

@ -9,7 +9,6 @@ class Block:
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)
@ -51,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."""
@ -72,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))."""
@ -89,4 +92,3 @@ class Block:
line += "%i" % self.data[(i*self.blockSizeR)+j]
print(line+"|")
print(dash)

View File

@ -100,4 +100,4 @@ class Observer:
"RxDup": {"mean": meanOrNan(RxDup), "max": maxOrNan(RxDup)},
}
return trafficStats
return trafficStats

View File

@ -16,6 +16,26 @@ 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
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."""
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
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."""

View File

@ -2,9 +2,8 @@
class Shape:
"""This class represents a set of parameters for a specific simulation."""
def __init__(self, blockSizeR, blockSizeRK, blockSizeC, blockSizeCK,
numberNodes, failureModel, failureRate, class1ratio, chiR, chiC, 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
@ -14,6 +13,7 @@ class Shape:
self.blockSizeCK = blockSizeCK
self.failureModel = failureModel
self.failureRate = failureRate
self.maliciousNodes = maliciousNodes
self.netDegree = netDegree
self.class1ratio = class1ratio
self.chiR = chiR
@ -28,7 +28,7 @@ class Shape:
def __repr__(self):
"""Returns a printable representation of the shape"""
shastr = ""
shastr += "bsrn-"+str(self.blockSizeR)
shastr += "-bsrn-"+str(self.blockSizeR)
shastr += "-bsrk-"+str(self.blockSizeRK)
shastr += "-bscn-"+str(self.blockSizeC)
shastr += "-bsck-"+str(self.blockSizeCK)
@ -45,9 +45,9 @@ 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):
"""Adds the random seed to the shape"""
self.randomSeed = seed

View File

@ -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
@ -59,7 +60,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
@ -73,8 +74,28 @@ class Simulator:
assignedRows = []
assignedCols = []
maliciousNodesCount = int((self.shape.maliciousNodes / 100) * self.shape.numberNodes)
remainingMaliciousNodes = maliciousNodesCount
for i in range(self.shape.numberNodes):
if self.config.evenLineDistribution:
if i == 0:
amImalicious_value = 0
else:
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 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
@ -88,7 +109,7 @@ class Simulator:
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), 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)
@ -97,7 +118,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:
@ -151,7 +172,7 @@ class Simulator:
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
@ -230,7 +251,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)
@ -238,13 +260,17 @@ class Simulator:
missingVector = []
progressVector = []
trafficStatsVector = []
malicious_nodes_not_added_count = 0
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):
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()
@ -307,6 +333,25 @@ 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
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)
progress = pd.DataFrame(progressVector)
if self.config.saveRCdist:
self.result.addMetric("rowDist", self.distR)
@ -314,5 +359,5 @@ 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

View File

@ -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,15 @@ 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.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)
@ -196,8 +205,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
@ -205,17 +216,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."""
@ -232,11 +249,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."""
@ -250,25 +270,27 @@ 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.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] :
return True
if not self.amImalicious:
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] :
return True
else:
return False # received or already sent
return False # received or already sent or malicious
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."""
if self.checkSegmentToNeigh(rID, cID, neigh):
if self.checkSegmentToNeigh(rID, cID, neigh) and not self.amImalicious:
self.sendSegmentToNeigh(rID, cID, neigh)
return True
else:
@ -283,16 +305,18 @@ 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):
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:
if cID in self.columnIDs and not self.amImalicious:
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
@ -317,19 +341,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
@ -345,32 +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.blockSizeR)
for neigh in neighs.values():
sentOrReceived = neigh.received | neigh.sent
if sentOrReceived.count(1) < self.sendLineUntilR:
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.blockSizeC)
for neigh in neighs.values():
sentOrReceived = neigh.received | neigh.sent
if sentOrReceived.count(1) < self.sendLineUntilC:
needed |= ~sentOrReceived
needed &= line
if (needed).any():
for i in range(len(needed)):
if needed[i]:
segmentsToSend.append((1, cID, i))
if not self.amImalicious:
for rID, neighs in self.rowNeighbors.items():
line = self.getRow(rID)
needed = zeros(self.shape.blockSizeR)
for neigh in neighs.values():
sentOrReceived = neigh.received | neigh.sent
if sentOrReceived.count(1) < self.sendLineUntilR:
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.blockSizeC)
for neigh in neighs.values():
sentOrReceived = neigh.received | neigh.sent
if sentOrReceived.count(1) < self.sendLineUntilC:
needed |= ~sentOrReceived
needed &= line
if (needed).any():
for i in range(len(needed)):
if needed[i]:
segmentsToSend.append((1, cID, i))
return segmentsToSend
def nextSegment():
@ -380,12 +405,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
@ -400,7 +425,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:
@ -425,7 +451,7 @@ class Validator:
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):
if self.checkSegmentToNeigh(rID, cID, neigh) and not self.amImalicious:
yield(rID, cID, neigh)
t = tries
if self.columnIDs:
@ -433,14 +459,15 @@ class Validator:
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):
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
@ -449,22 +476,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
@ -489,14 +518,17 @@ 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.
self.restoreRowCount += 1
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):
@ -507,14 +539,17 @@ 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.
self.restoreColumnCount += 1
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):
@ -542,4 +577,4 @@ class Validator:
if a == e:
validated+=1
return arrived, expected, validated
return arrived, expected, validated

View File

@ -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))
@ -274,4 +259,4 @@ class Visualizer:
plt.ylabel('Price')
#Test
plt.show()
plt.show()

View File

@ -1,23 +1,33 @@
#!/bin/python3
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
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":
plt.text(xDes, conf["yaxismax"]/3, conf["textBox"], fontsize=10, verticalalignment='top', bbox=props)
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])
if conf["type"] == "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=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=conf["line_label"])
plt.title(conf["title"])
plt.ylabel(conf["ylabel"])
plt.xlabel(conf["xlabel"])
@ -25,6 +35,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"""
@ -39,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
@ -69,6 +93,32 @@ class Visualizor:
def plotHeatmaps(self, x, y):
"""Plot the heatmap using the parameters given as x axis and y axis"""
print("Plotting heatmap "+x+" vs "+y)
#Find the location of x in shape
#Find the location of y in shape
#Find the location od r in shape
#Loop over all results
#Add unique values foir every parameter
#Find number of runs from r
#If number of values for x and y > 3 then plot heatmap, otherwise finish
#Create a 2D grid with the dimensions of the number of values for x and y
#For all values of x
#For all values of y
# For all values in r
#Fixing all other values to 1 (in the mean time)
#Add/sum TTA into 2D grid
#if last r divide by number of runs
#Plot 2D grid
def plotAll(self):
"""Plot all the important elements of each result"""
for result in self.results:
@ -79,17 +129,573 @@ class Visualizor:
self.plotSentData(result, plotPath)
self.plotRecvData(result, plotPath)
self.plotDupData(result, plotPath)
if self.config.saveRCdist:
self.plotRowCol(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)
# self.plotBoxSamplesRepaired(result, plotPath)
# 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)
self.plotBoxenSamplesRepaired(result, plotPath)
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)
self.plotECDFSamplesRepaired(result, plotPath)
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 = {}
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"
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"])
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"))
def plotBoxRestoreColumnCount(self, result, plotPath):
"""Box Plot of restoreColumnCount for all nodes"""
plt.clf()
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']+"\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"
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"])
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"))
def plotBoxenRestoreRowCount(self, result, plotPath):
"""Plots the Boxen plot of restoreRowCount for all nodes"""
plt.clf()
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']+"\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"
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 = {}
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"
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 = {}
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"
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 = {}
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"
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()
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']+"\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"
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"))
def plotECDFMessagesRecv(self, result, plotPath):
"""Plots the ECDF of messages received by all nodes using seaborn's ecdfplot"""
plt.clf()
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']+"\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"
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"))
def plotECDFSamplesReceived(self, result, plotPath):
"""Plots the ECDF of samples received by all nodes using seaborn's ecdfplot"""
plt.clf()
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']+"\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"
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"))
def plotECDFRowColDist(self, result, plotPath):
"""Plots the ECDF of row col distance by all nodes using seaborn's ecdfplot"""
plt.clf()
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']+"\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"
vector1 = result.metrics["rowDist"]
vector2 = result.metrics["columnDist"]
n1 = int(result.numberNodes * result.class1ratio)
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"))
def plotECDFSamplesRepaired(self, result, plotPath):
"""Plots the ECDF of samples repaired by all nodes using seaborn's ecdfplot"""
plt.clf()
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']+"\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"
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"))
def plotBoxenSamplesRecv(self, result, plotPath):
"""Boxen Plot of the number of samples received by all nodes"""
plt.clf()
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']+"\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"
n1 = int(result.numberNodes * result.class1ratio)
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"])
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()
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 = {}
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"
n1 = int(result.numberNodes * result.class1ratio)
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"])
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()
print("Plot %s created." % (plotPath + "/boxen_samplesRepaired.png"))
def plotBoxenRowColDist(self, result, plotPath):
"""Boxen Plot of the Row/Column distribution"""
plt.clf()
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']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd']
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"])
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()
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 = {}
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"
n1 = int(result.numberNodes * result.class1ratio)
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"])
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"))
def plotBoxenMessagesRecv(self, result, plotPath):
"""Plots the number of messages received by all nodes using seaborn's boxenplot"""
plt.clf()
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']+"\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"
n1 = int(result.numberNodes * result.class1ratio)
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"])
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"))
def plotBoxSamplesRepaired(self, result, plotPath):
"""Box Plot of the number of samples repaired by all nodes"""
plt.clf()
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']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd']
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+1: ]]
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 = {}
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"
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 = {}
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
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 = {}
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
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 = {}
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
conf["desLoc"] = 1
conf["xlabel"] = "Nodes"
conf["ylabel"] = "Percentage of samples received (%)"
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)
conf["path"] = plotPath + "/sampleRecv.png"
maxi = max(conf["data"])
# 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
conf["line_label1"] = "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"])
def plotBoxSampleRecv(self, result, plotPath):
"""Box Plot of the sampleRecv for each node"""
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']+"\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
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+1: ]]
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 = {}
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"] = "Missing Samples"
conf["type"] = "plot"
conf["type"] = "plot_with_1line"
conf["legLoc"] = 1
conf["desLoc"] = 1
conf["colors"] = ["m-"]
@ -104,18 +710,21 @@ 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)
conf["line_label"] = "Total samples to deliver"
plotData(conf)
print("Plot %s created." % conf["path"])
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 = {}
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
@ -147,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
@ -177,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
@ -207,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
@ -238,9 +847,9 @@ 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"] = "bar"
conf["type"] = "grouped_bar"
conf["legLoc"] = 2
conf["desLoc"] = 2
conf["colors"] = ["r+", "b+"]
@ -258,3 +867,98 @@ 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 = {}
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
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 plotBoxMessagesSent(self, result, plotPath):
"""Box Plot of the number of messages sent by all nodes"""
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']+"\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"
n1 = int(result.numberNodes * result.class1ratio)
conf["data"] = [result.msgSentCount[1: n1], result.msgSentCount[n1+1: ]]
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"""
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']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd']
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"])
def plotBoxMessagesRecv(self, result, plotPath):
"""Plots the number of messages received by all nodes"""
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']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd']
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+1: ]]
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"""
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']+"\nMalicious Node: "+attrbs['mn']+"\nNetwork degree: "+attrbs['nd']
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"])

View File

@ -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 = range(3)
@ -56,21 +52,22 @@ failureModels = ["random"]
# Percentage of block not released by producer
failureRates = range(40, 81, 20)
# Block size in one dimension in segments. Block is blockSizes * blockSizes segments.
blockSizes = range(64, 113, 128)
# Percentage of nodes that are considered malicious
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 = 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 = [1]
validatorsPerNode2 = [500]
validatorsPerNode1 = [10]
validatorsPerNode2 = [50]
# Set uplink bandwidth in megabits/second
bwUplinksProd = [200]
@ -101,13 +98,17 @@ diagnostics = False
# True to save git diff and git commit
saveGit = False
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 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 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:
blockSizeR = blockSizeC = blockSize
blockSizeRK = blockSizeCK = blockSize // 2
chiR = chiC = chi
shape = Shape(blockSizeR, blockSizeRK, blockSizeC, blockSizeCK, nn, fm, fr, class1ratio, chiR, chiC, vpn1, vpn2, netDegree, bwUplinkProd, bwUplink1, bwUplink2, run)
shape = Shape(blckSizeR, blckSizeRK, blckSizeC, blckSizeCK, nn, fm, fr, mn, class1ratio, chR, chC, vpn1, vpn2, netDegree, bwUplinkProd, bwUplink1, bwUplink2, run)
yield shape