Skip to content
Snippets Groups Projects
Commit 5b11ae58 authored by Maria Hartmann's avatar Maria Hartmann
Browse files

added heap implementations, experimental scripts, results and plots

parent 08a1489f
No related branches found
No related tags found
No related merge requests found
Showing
with 1577 additions and 0 deletions
randomness parameter value;Pairing;Smooth
randomness parameter value;0;12
1e-05;3.3110000000000004;0.9997999999999998
0.01001;9.695700000000002;10.025450000000001
0.02001;10.85029;11.63291
0.03001;11.54132;12.58502
0.040010000000000004;12.00077;13.229379999999999
0.050010000000000006;12.386989999999999;13.76429
0.06001;12.68024;14.18097
0.07001;12.901870000000002;14.504279999999998
0.08001;13.10722;14.776249999999997
0.09000999999999999;13.286290000000001;15.04036
0.10001;13.454849999999999;15.25796
0.11001;13.583470000000002;15.44508
0.12000999999999999;13.70061;15.617080000000001
0.13001000000000001;13.79743;15.745219999999998
0.14001000000000002;13.926459999999999;15.91376
0.15001;14.00538;16.05316
0.16001;14.084409999999998;16.14607
0.17001000000000002;14.157020000000001;16.25582
0.18001;14.223750000000003;16.3467
0.19001;14.300799999999999;16.46123
0.20001000000000002;14.33816;16.52597
0.21001;14.4027;16.58205
0.22001;14.437909999999999;16.66046
0.23001000000000002;14.500430000000001;16.726419999999997
0.24001;14.531600000000001;16.78245
0.25001;14.58332;16.8614
0.26001;14.613059999999997;16.90503
0.27001000000000003;14.6482;16.94697
0.28001000000000004;14.68594;17.00532
0.29001;14.715880000000002;17.047040000000003
randomness parameter value;Pairing;Smooth
randomness parameter value;0;12
1e-05;3.3110000000000004;0.9997999999999998
0.01001;9.695700000000002;6.3199499999999995
0.02001;10.85029;7.162200000000001
0.03001;11.54132;7.654059999999999
0.040010000000000004;12.00077;7.984989999999999
0.050010000000000006;12.386989999999999;8.26281
0.06001;12.68024;8.46781
0.07001;12.901870000000002;8.63679
0.08001;13.10722;8.77514
0.09000999999999999;13.286290000000001;8.90821
0.10001;13.454849999999999;9.01913
0.11001;13.583470000000002;9.11216
0.12000999999999999;13.70061;9.2018
0.13001000000000001;13.79743;9.27063
0.14001000000000002;13.926459999999999;9.354729999999998
0.15001;14.00538;9.421119999999998
0.16001;14.084409999999998;9.46995
0.17001000000000002;14.157020000000001;9.527839999999998
0.18001;14.223750000000003;9.57139
0.19001;14.300799999999999;9.629190000000001
0.20001000000000002;14.33816;9.65897
0.21001;14.4027;9.688220000000001
0.22001;14.437909999999999;9.73125
0.23001000000000002;14.500430000000001;9.761690000000002
0.24001;14.531600000000001;9.79034
0.25001;14.58332;9.8314
0.26001;14.613059999999997;9.85144
0.27001000000000003;14.6482;9.87486
0.28001000000000004;14.68594;9.90154
0.29001;14.715880000000002;9.924119999999998
randomness parameter value;Pairing;Smooth;Smooth18
randomness parameter value;0;12;14
2;0.5;1.0;0.5
4;1.35;1.6;1.15
8;2.025;2.6999999999999997;2.1500000000000004
16;3.5125;4.050000000000001;3.3875
32;5.05;5.3125;4.5625
64;6.4624999999999995;6.878125000000001;6.05625
128;7.93125;8.309375;7.4609375
256;9.46328125;9.95703125;9.011718750000002
512;10.770703125;11.534765625;10.562890625
1024;12.1029296875;13.253320312500001;12.276562499999999
2048;13.376953125;14.994335937499999;13.99287109375
4096;14.676660156250001;16.67939453125;15.68359375
8192;15.946264648437499;18.4197021484375;17.4177490234375
16384;17.20384521484375;20.120104980468753;19.1246826171875
randomness parameter value;Pairing;Smooth;Smooth18
randomness parameter value;0;12;14
2;0.5;0.0;0.5
4;1.35;0.6;1.0499999999999998
8;2.025;1.3;1.65
16;3.5125;2.2125000000000004;2.45
32;5.05;3.0250000000000004;3.18125
64;6.4624999999999995;4.034375;4.121875
128;7.93125;4.8203125;4.8984375
256;9.46328125;5.690625000000001;5.715624999999999
512;10.770703125;6.578125;6.59453125
1024;12.1029296875;7.459765625;7.472460937500001
2048;13.376953125;8.35986328125;8.36083984375
4096;14.676660156250001;9.222314453125;9.225439453125
8192;15.946264648437499;10.109228515625;10.107202148437498
16384;17.20384521484375;10.96829833984375;10.96964111328125
randomness parameter value;Pairing;Smooth
randomness parameter value;0;12
2;0.0;0.0
4;0.65;0.6375
8;1.23125;1.2812499999999998
16;1.6718750000000004;1.7125000000000001
32;2.2546875;2.109375
64;2.5328125;2.51640625
128;2.7156249999999997;2.7628906250000003
256;3.0244140624999996;2.932421875
512;3.17080078125;3.091015625
1024;3.230126953125;3.182617187499999
2048;3.3331298828125;3.2513427734374996
4096;3.3716308593749997;3.2977294921875004
8192;3.4386779785156256;3.3528076171875
16384;3.4799468994140628;3.3715332031249994
32768;3.4966629028320315;3.3828002929687506
65536;3.5240753173828128;3.3962371826171878
131072;3.5682422637939446;3.4042907714843755
randomness parameter value;Pairing;Smooth
randomness parameter value;0;12
2;0.0;0.0
4;0.65;0.5625000000000002
8;1.23125;1.0187499999999998
16;1.6718750000000004;1.3375
32;2.2546875;1.55
64;2.5328125;1.80078125
128;2.7156249999999997;1.9242187499999999
256;3.0244140624999996;1.9865234375000003
512;3.17080078125;2.07734375
1024;3.230126953125;2.1288574218750007
2048;3.3331298828125;2.155859375
4096;3.3716308593749997;2.1764892578125
8192;3.4386779785156256;2.2006591796875
16384;3.4799468994140628;2.2073852539062497
32768;3.4966629028320315;2.211355590820313
65536;3.5240753173828128;2.215667724609375
131072;3.5682422637939446;2.218004608154297
randomness parameter value;Pairing;Smooth
randomness parameter value;0;12
1900;7.140770000000002;6.0651
1800;7.261944999999999;6.198515
1700;7.313929999999999;6.256444999999999
1600;7.462670000000001;6.48028
1500;7.5541849999999995;6.535635000000001
1400;7.711180000000001;6.737559999999998
1300;7.786554999999999;6.852745
1200;7.948655000000001;7.065579999999999
1100;8.04499;7.18305
1000;8.25514;7.484164999999999
900;8.48538;7.764014999999999
800;8.644215;7.9804650000000015
700;8.897675;8.31422
600;9.121414999999999;8.6109
500;9.441964999999998;9.036955
400;9.87564;9.61485
300;10.334719999999999;10.22929
200;10.993725;11.170739999999999
100;12.144270000000002;12.770485
randomness parameter value;Pairing;Smooth
randomness parameter value;0;12
1900;7.140770000000002;4.111149999999999
1800;7.261944999999999;4.206099999999998
1700;7.313929999999999;4.23051
1600;7.462670000000001;4.356905000000001
1500;7.5541849999999995;4.397234999999999
1400;7.711180000000001;4.501015000000001
1300;7.786554999999999;4.575859999999999
1200;7.948655000000001;4.6985
1100;8.04499;4.7659400000000005
1000;8.25514;4.933224999999999
900;8.48538;5.093285
800;8.644215;5.216295
700;8.897675;5.39767
600;9.121414999999999;5.562875000000001
500;9.441964999999998;5.790405
400;9.87564;6.099679999999998
300;10.334719999999999;6.429255
200;10.993725;6.9218
100;12.144270000000002;7.751835000000001
randomness parameter value;Pairing;Smooth
randomness parameter value;0;12
2;0.0;0.0
4;0.7000000000000001;0.6000000000000001
8;1.6749999999999998;1.6500000000000001
16;2.9875;3.025
32;4.05625;4.14375
64;5.71875;5.665625
128;7.171875;7.395312499999999
256;8.4984375;8.960156249999999
512;9.845703125;10.61015625
1024;11.176171875;12.24921875
2048;12.404296875000002;13.93369140625
4096;13.6794921875;15.63544921875
8192;14.9508056640625;17.39541015625
16384;16.2085693359375;19.12520751953125
32768;17.44716796875;20.857037353515626
65536;18.6917236328125;22.592379760742183
131072;19.929542541503906;24.330378723144527
randomness parameter value;Pairing;Smooth
randomness parameter value;0;12
2;0.0;0.0
4;0.7000000000000001;0.55
8;1.6749999999999998;1.25
16;2.9875;2.1624999999999996
32;4.05625;2.8999999999999995
64;5.71875;3.8562499999999997
128;7.171875;4.846875
256;8.4984375;5.70703125
512;9.845703125;6.605078125
1024;11.176171875;7.468554687500001
2048;12.404296875000002;8.33544921875
4096;13.6794921875;9.20283203125
8192;14.9508056640625;10.0988037109375
16384;16.2085693359375;10.96561279296875
32768;17.44716796875;11.841461181640625
65536;18.6917236328125;12.714126586914062
131072;19.929542541503906;13.582135009765626
node.py 0 → 100755
#!/usr/bin/python3
class Node:
def __init__(self, key):
#for now contains all pointers that might be needed in any implementation
#idea is to use only necessary ones in each implementation
self.key = key
self.parent = None
self.leftChild = None
self.rightChild=None
self.nextSibling=None
self.prevSibling=None
self.leftOnly=False
self.rightOnly=False
self.vertex=None #for testing with Dijkstra's algorithm
#!/usr/bin/python3
from node import Node
from pairing_heap_interface import PairingHeapInterface
from pairing_heap_standard import PairingHeapStandard
from smooth_heap import SmoothHeap
from pairing_heap_l import PairingHeapL
from smooth_heap_l import SmoothHeapL
COUNT_TYPE_LINKS=-1
COUNT_TYPE_COMPS=-2
COUNT_TYPE_BOTH=0
class PairingHeap(PairingHeapInterface):
MODES={21:"Pairing_L", 22:"Smooth_L"}
mode=0
countType=COUNT_TYPE_COMPS
heap=None
def __init__(self, mode=0, countType=COUNT_TYPE_COMPS):
self.mode=mode
self.countType=countType
def make_heap(self):
if self.mode==0:
self.heap=PairingHeapStandard()
elif self.mode==12:
self.heap=SmoothHeap()
elif self.mode==21:#root list version, everything lazy, to be used for Dijkstra test in paper
self.heap=PairingHeapL()
elif self.mode==22:#root list version, everything lazy, to be used for Dijkstra test in paper
self.heap=SmoothHeapL()
else:
raise Exception("Invalid heap ID! No heap of type ID {} is implemented.")
def find_min(self):
#Careful! Implementation is inconsistent across pairing heap types.
return self.heap.find_min()
def insert(self, node):
#inserts node; returns number of linking operations performed
result=self.heap.insert(node)
if isinstance(result, tuple):
if self.countType==COUNT_TYPE_BOTH:
return (result[0], result[1])#(comps, links)
else:
return result[2+self.countType]
else:#result should be single number iff link count and comp count are the same
if self.countType==COUNT_TYPE_BOTH:
return (result, result)
else:
return result
def delete_min(self):
#deletes min; returns number of linking operations/comparisons performed
result=self.heap.delete_min()
if len(result)==3:
if self.countType==COUNT_TYPE_BOTH:
return (result[0], result[1], result[2])#min, comps, links
else:
return (result[0],result[3+self.countType])
else:#result should be 2-tuple iff link count and comp count are the same
if self.countType==COUNT_TYPE_BOTH:
return (result[0], result[1], result[1])
else:
return result
def merge(self, heap2):
#merges this heap and heap 2; returns number of linking operations performed
result = self.heap.merge(heap2)
if isinstance(result, tuple):
if self.countType==COUNT_TYPE_BOTH:
return (result[0], result[1])#(comps, links)
else:
return result[2+self.countType]
else:#result should be single number iff link count and comp count are the same
if self.countType==COUNT_TYPE_BOTH:
return (result, result)
else:
return result
def delete(self, node):
self.heap.delete(node)
def decrease_key(self, node, diff):
result = self.heap.decrease_key(node, diff)
if isinstance(result, tuple):
if self.countType==COUNT_TYPE_BOTH:
if result[0]==None or result[1]==None:
print("heap {} returns None".format(self.MODES[self.mode]))
return (result[0], result[1])#(comps, links)
else:
return result[2+self.countType]
else:#result should be single number iff link count and comp count are the same
if self.countType==COUNT_TYPE_BOTH:
if result==None:
print("heap {} returns None".format(self.MODES[self.mode]))
return (result, result)
else:
return result
#!/usr/bin/python3
from node import Node
class PairingHeapInterface:
def __init__(self):
self.count = 0
def make_heap(self):
pass
def find_min(self):
pass
def insert(self, node):
pass
def delete_min(self):
pass
def merge(self, heap2):
pass
def delete(self, node):
pass
#!/usr/bin/python3
from node import Node
from pairing_heap_interface import PairingHeapInterface
class PairingHeapL(PairingHeapInterface):
# lazy variant of standard pairing heap (maintaining root-list and consolidating only upon extract-min)
forest=[] #list storing roots of all top-level trees
def __init__(self, root=None):
self.forest=[]
if root!=None:
root.parent=None
self.forest+=[root]
def listInorder(self):
forestList=[]
for root in self.forest:
forestList+=[self.listInorderTree(root)]
return forestList
def listInorderTree(self, root):
if root==None:
return []
else:
return self.listInorderTree(root.leftChild)+[root.key]+self.listInorderTree(root.nextSibling)
def insert(self, node):
#concatenates node to list of trees; returns number of linking ops (always 0) for sake of consistency
#print("trying to insert {}...".format(node.key))
if node==None:
return 0
node.parent=None
self.forest+=[node]
return 0
def pairing(self):
fs = len(self.forest)
#performs pairing pass and returns number of linking operations
linkCount=0
if fs<2:
return 0
else:
pairedForest=[]
index=-1
for i in range(0, fs, 2): # pairing pass
if i==fs-1: #last tree if length of forest is odd-numbered
pairedForest+=[self.forest[i]]#concatenate to new forest (no linking required)
else:#pair trees
if self.forest[i].key<=self.forest[i+1].key:
if self.forest[i].leftChild==None:
self.forest[i+1].parent=self.forest[i]
else:
self.forest[i+1].nextSibling=self.forest[i].leftChild
self.forest[i].leftChild=self.forest[i+1]
pairedForest+=[self.forest[i]]
else:
if self.forest[i+1].leftChild==None:
self.forest[i].parent=self.forest[i+1]
else:
self.forest[i].nextSibling=self.forest[i+1].leftChild
self.forest[i+1].leftChild=self.forest[i]
pairedForest+=[self.forest[i+1]]
self.forest=pairedForest
##print("Result of 1st round {}.".format(self.listInorder()))
index = len(self.forest)-1
for i in range(len(self.forest)-2, -1, -1): # combining pass
if self.forest[index].key<=self.forest[i].key:
if self.forest[index].leftChild==None:
self.forest[i].parent=self.forest[index]
else:
self.forest[i].nextSibling=self.forest[index].leftChild
self.forest[index].leftChild=self.forest[i]
else:
if self.forest[i].leftChild==None:
self.forest[index].parent=self.forest[i]
else:
self.forest[index].nextSibling=self.forest[i].leftChild
self.forest[i].leftChild=self.forest[index]
index=i
self.forest=[self.forest[index]]
##print("Result of 2nd round {}.".format(self.listInorder()))
return (fs-1)
def delete_min(self):
#finds and deletes min; restructures forest; returns number of linking operations
linkCount=0
compCount=0
cn = self.pairing()
assert len(self.forest)==1
#if (len(self.forest)==0):
# print("Cannot delete min of empty heap")
# return (None,0,0)
currentSibling=self.forest[0].leftChild
while currentSibling!=None:
nextSibling=currentSibling.nextSibling
self.forest+=[currentSibling]
currentSibling.nextSibling=None
currentSibling=nextSibling
self.forest[-1].parent=None #only for the last concatenated sibling as only this one carried parent pointer
minNode = self.forest[0]
self.forest=self.forest[1:]
##print("Result of delete-min {}.".format(self.listInorder()))
###print('**')
###print(minNode.key)
return (minNode, cn, cn)
def decrease_key(self, node, diff):
linkCount=0
if node==None or diff<=0:
return 0
elif node.parent==None and node.nextSibling==None: #node is root
node.key=node.key-diff
else:
self.unlink_node(node)
node.key=node.key-diff
self.forest+=[node]
return 0
def merge(self, heap2):
#concatenates forests of this heap and heap2; returns number of link operations (always 0) for consistency
#print("Trying to merge {} and {}.".format(self.listInorder(), heap2.listInorder()))
self.forest+=heap2.forest
#print("Result of merge is {}.".format(self.listInorder()))
return 0
def delete(self, node):
if node==None:
print("Cannot delete None")
return
elif node.parent==None and node.nextSibling==None: #node is root
print("Trying to delete {}...".format(node.key))
index=self.forest.index(node)#slight cheating; would be nicer to use a linked list as forest instead
#remove node from forest list
self.forest=self.forest[:index]+self.forest[index+1:]
else: #node is a child somewhere
print("Trying to delete {}...".format(node.key))
self.unlink_node(node)
#concatenate potential children to forest list
sibling=node.leftChild
while sibling!=None:
self.forest+=[sibling]
sibling=sibling.nextSibling
if sibling!=None:
self.forest[-1].nextSibling=None
else:
self.forest[-1].parent=None
print("Result of deletion of {} is {}.".format(node.key, self.listInorder()))
def unlink_node(self, node):
#for non-root nodes only (does nothing about forest list, only tree-internal links)
if node==None:
return
else:
if node.nextSibling!=None:
temp=node.nextSibling
while temp.nextSibling!=None:#find rightmost child
temp=temp.nextSibling
if temp.parent.leftChild==node:#node is leftmost child
#link parent to next sibling
temp.parent.leftChild=node.nextSibling
node.nextSibling=None
else:
#node is neither first nor last child of parent
prevSibling=temp.parent.leftChild
while prevSibling.nextSibling!=node:#find left (previous) sibling
prevSibling=prevSibling.nextSibling
prevSibling.nextSibling=node.nextSibling #cut out node, link left and right sibling
node.nextSibling=None
else:
#node is rightmost child of parent
if node.parent.leftChild==node:
#node is only child: just remove
node.parent.leftChild=None
else:
prevSibling=node.parent.leftChild
while prevSibling.nextSibling!=node:#find left (previous) sibling
prevSibling=prevSibling.nextSibling
prevSibling.parent=node.parent
prevSibling.nextSibling=None
node.parent=None
#!/usr/bin/python3
from node import Node
from pairing_heap_interface import PairingHeapInterface
class PairingHeapStandard(PairingHeapInterface):
#performs a left-to-right forward pass, then a backward combining pass
#TODO: left/right child (page 115)
def __init__(self, root=None):
self.root=root
def make_heap(self):
#this is equivalent to init
pass
def listInorder(self, root):
if(root==None):
return []
return self.listInorder(root.leftChild)+[root.key]+self.listInorder(root.nextSibling)
def find_min(self):
if self.root==None:
return None
else:
return self.root
def insert(self, node):
#inserts node as child of root, returns number of link operations
linkCount=0
#print("trying to insert {}...".format(node.key))
if self.root==None:
#heap was empty before
self.root=node
else:
newheap=PairingHeapStandard(node)
linkCount=self.merge(newheap)
#print(self.listInorder(self.root))
return linkCount
def delete_min(self):
#print("trying to delete min...")
linkCount=0 #counts number of linking operations
minKey=None
minNode=None
if self.root==None:
print("Heap was already empty.")
return (minNode,linkCount)
elif self.root.leftChild==None:
#heap contained only one element
minNode=self.root
self.root=None
return (minNode, linkCount)
elif self.root.leftChild.nextSibling==None:
#first child has no siblings->first child becomes root
minNode=self.root
self.root=self.root.leftChild
self.root.parent=None
return (minNode, linkCount)
else:
minNode=self.root
self.root=self.root.leftChild
current=self.root
nextSibling=None
heaps=[]
paired=[]
#left-to-right pairing pass v2
while current!=None:#create heaps of all orphaned children
nextSibling=current.nextSibling
heaps+=[PairingHeapStandard(current)]
current.nextSibling=None
current=nextSibling
for j in range(0,len(heaps),2):
if(j==len(heaps)-1):#last one
paired+=[heaps[j]]
else:
heap=heaps[j]
linkCount+=heap.merge(heaps[j+1])#merge returns its number of link operations
paired+=[heap]
#combining backwards pass v2
combined=paired[-1]#start with last tree
for i in range(len(paired)-2, -1, -1):
linkCount+=combined.merge(paired[i])#merge returns its number of link operations
self.root=combined.root
self.root.parent=None
#print("result is {}".format(self.listInorder(self.root)))
return (minNode, linkCount)
def merge(self, heap2):
linkCount=0 #counts number of linking operations
#print("Trying to merge {} and {}...".format(self.listInorder(self.root), self.listInorder(heap2.root)))
if self.root==None:#heap is empty
self.root=heap2.root
elif heap2.root==None:#heap 2 is empty
pass #this heap is the result
else:
if self.root.key<=heap2.root.key:
heap2.root.nextSibling=self.root.leftChild
if heap2.root.nextSibling==None:
heap2.root.parent=self.root
self.root.leftChild=heap2.root
linkCount=1
else:
self.root.nextSibling=heap2.root.leftChild
if self.root.nextSibling==None:
self.root.parent=heap2.root
heap2.root.leftChild=self.root
self.root=heap2.root
linkCount=1
#TODO check for only children?
#print("Result is {}".format(self.listInorder(self.root)))
return linkCount
def decrease_key(self, node, diff):#TODO more testing
linkCount=0
if self.root==node:
self.root.key=self.root.key-diff
else:
#first step: cut node from heap
self.unlink_node(node)#helper function
#second step: decrease key
subheap=PairingHeapStandard(node)
subheap.root.key=subheap.root.key-diff
#third step: merge back in
linkCount = self.merge(subheap)
return linkCount
def delete(self, node): #TODO more testing?
print("trying to delete {} from {}".format(node.key, self.listInorder(self.root)))
if self.root.key==node.key:
self.delete_min()
else:
self.unlink_node(node)#helper function
subheap=PairingHeapStandard(node)
subheap.delete_min()
self.merge(subheap)
print("result is {}".format(self.listInorder(self.root)))
pass
def unlink_node(self, node):
#removes node from heap updating pointers
if self.root==node:#remove the whole heap
self.root=None
else:
if node.nextSibling!=None:
temp=node.nextSibling
while temp.nextSibling!=None:
temp=temp.nextSibling
if temp.parent.leftChild==node:#node is leftmost child
#link parent to next sibling
temp.parent.leftChild=node.nextSibling
node.nextSibling=None
else:
#node is neither first nor last child of parent
prevSibling=temp.parent.leftChild
while prevSibling.nextSibling!=node:#find left (previous) sibling
prevSibling=prevSibling.nextSibling
prevSibling.nextSibling=node.nextSibling #cut out node, link left and right sibling
else:
#node is rightmost child of parent
if node.parent.leftChild==node:
#node is only child: just remove
node.parent.leftChild=None
else:
prevSibling=node.parent.leftChild
while prevSibling.nextSibling!=node:#find left (previous) sibling
prevSibling=prevSibling.nextSibling
prevSibling.parent=node.parent
prevSibling.nextSibling=None
node.parent=None
#!/usr/bin/python3
from node import Node
from pairing_heap_interface import PairingHeapInterface
from pairing_heap import PairingHeap
import networkx as nx
import sys
import random
import math
import numpy as np
import matplotlib.pyplot as plt
import os
import psutil
import csv
COUNT_TYPE_BOTH = 0
COUNT_TYPE_LINKS = -1
COUNT_TYPE_COMPS = -2
TYPES = {21: "Pairing", 22: "Smooth"}
MAX_TYPE_KEY = max(TYPES.keys())
#COLOURS = ['xkcd:fire engine red', 'xkcd:dusty orange', 'xkcd:clear blue', 'xkcd:cool green',
# 'xkcd:macaroni and cheese', 'xkcd:fire engine red', 'xkcd:dusty orange', 'xkcd:clear blue',
# 'xkcd:cool green', 'xkcd:macaroni and cheese', 'xkcd:bright sky blue', 'xkcd:bright sky blue', 'xkcd:green',
# 'xkcd:ochre', 'xkcd:sea blue', 'xkcd:sea green', 'xkcd:sea blue', 'xkcd:warm grey',
# 'xkcd:bright sky blue', 'xkcd:bright sky blue']
LINETYPES = 5 * ['-'] + 5 * ['--'] + ['--', '-'] + ['--', '--', '--', '--', '--', '--', '-', '-']
FIG_LABELS = ["comparisons", "links"]
MAX_TYPE_KEY = max(TYPES.keys())
COLOURS = {21:'xkcd:fire engine red', 22:'xkcd:sea green'}
SHADE_COLOURS = {21:'#fe4d4e', 22:'#58ab8e'}
NUMBER_TESTS = 10 # number of tests to run
TEST_SIZE = 500 # ,6000,7000,8000,9000,10000,20000,30000,40000,50000,60000,70000,80000,90000,100000
EDGE_PROBABILITY = 0.05
WEIGHT_RANGE = 10000
def plot_avg_counts_old(avgCounts):
# colours from https://xkcd.com/color/rgb/
linetypes = 5 * ["-"] + 5 * ["--"] + ["--", "-"] + ["-, -"]
plt.figure('Dijkstra with variable connectivity')
for k in TYPES.keys():
avgComps = [acounts[k] for acounts in avgCounts[0]]
plt.plot([factor * EDGE_PROBABILITY for factor in range(1, 101, 1)], avgComps, color=COLOURS[k], linestyle='-',
label=TYPES[k] + " comparisons")
avgLinks = [acounts[k] for acounts in avgCounts[1]]
plt.plot([factor * EDGE_PROBABILITY for factor in range(1, 101, 1)], avgLinks, color=COLOURS[k], linestyle='--',
label=TYPES[k] + " links")
plt.grid(True)
plt.legend(loc='best')
plt.show()
def plot_avg_counts(avgCounts):
# colours from https://xkcd.com/color/rgb/
MARKERS_COMP = {21:"o", 12:"d", 22:"^"}#https://matplotlib.org/3.1.1/api/markers_api.html
MARKERS_LINK = {21:"o", 12:"D", 22:"D"}
plt.figure('avg number of operations in Dijkstra\'s algorithm')
deviations = [factor * EDGE_PROBABILITY for factor in range(1, 21, 1)]
for k in TYPES.keys():
#print(k)
avgComps = [acounts[k] for acounts in avgCounts[0]]
maxComps = [acounts[k] for acounts in avgCounts[2]]
minComps = [acounts[k] for acounts in avgCounts[4]]
plt.plot(deviations, avgComps, color=COLOURS[k], linestyle="-", marker=MARKERS_COMP[k], markerfacecolor=COLOURS[k], markersize=9, markeredgewidth=1, markeredgecolor='black', label=TYPES[k] + " comparisons")
plt.fill_between(deviations, minComps, maxComps, color=SHADE_COLOURS[k], alpha=.3)
avgLinks = [acounts[k] for acounts in avgCounts[1]]
maxLinks = [acounts[k] for acounts in avgCounts[3]]
minLinks = [acounts[k] for acounts in avgCounts[5]]
plt.plot(deviations, avgLinks, color=COLOURS[k], linestyle="--", marker=MARKERS_LINK[k], markerfacecolor=COLOURS[k], markersize=9, markeredgewidth=1, markeredgecolor='black', label=TYPES[k] + " links")
plt.fill_between(deviations, minLinks, maxLinks, color=SHADE_COLOURS[k], alpha=.3)
plt.xlabel('Edge probability', fontsize=26)
plt.ylabel('Avg. number of operations / size', fontsize=26)
plt.xticks(fontsize=20)
plt.yticks(fontsize=20)
plt.rc('legend',fontsize=26) # using a size in points
plt.legend()
plt.grid(True)
#plt.gca().invert_xaxis()
figure = plt.gcf() # get current figure
figure.set_size_inches(16, 18) # set figure's size manually to full screen
plt.savefig('plots/paper-dijkstra-new.svg', bbox_inches='tight') # bbox_inches removes extra white spaces
plt.legend(loc='best')
plt.show()
def export_results(xs, results, countType, heapTypes, filename="dijkstra"):
# parse data as randomness parameter; counts per heap type
if countType == COUNT_TYPE_BOTH:
with open("data/" + filename + '-comps.csv', 'w', newline='') as csvfile:
csvwriter = csv.writer(csvfile, delimiter=';', quotechar='|', quoting=csv.QUOTE_MINIMAL)
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.values()])
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.keys()])
for i in range(len(results[0])):
row = [xs[i]] + [results[0][i][k] for k in TYPES.keys()]
csvwriter.writerow(row)
with open("data/" + filename + '-links.csv', 'w', newline='') as csvfile:
csvwriter = csv.writer(csvfile, delimiter=';', quotechar='|', quoting=csv.QUOTE_MINIMAL)
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.values()])
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.keys()])
for i in range(len(results[1])):
row = [xs[i]] + [results[1][i][k] for k in TYPES.keys()]
csvwriter.writerow(row)
else:
fn = "data/" + filename + '-links.csv' if countType == COUNT_TYPE_LINKS else "data/" + filename + '-comps.csv'
with open(fn, 'w', newline='') as csvfile:
csvwriter = csv.writer(csvfile, delimiter=';', quotechar='|', quoting=csv.QUOTE_MINIMAL)
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.values()])
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.keys()])
for i in range(len(results)):
row = [xs[i]]+[results[i][k] for k in TYPES.keys()]
csvwriter.writerow(row)
if __name__ == "__main__":
testOutputCount = []
avgLinksPerSize = []
avgCompsPerSize = []
maxLinksPerSize = []
maxCompsPerSize = []
minLinksPerSize = []
minCompsPerSize = []
xs = [factor * EDGE_PROBABILITY for factor in range(1, 21, 1)]
for x in xs:
avgCountsLinks = [0 for _ in range(MAX_TYPE_KEY + 1)]
avgCountsComps = [0 for _ in range(MAX_TYPE_KEY + 1)]
maxCountsLinks = [0 for _ in range(MAX_TYPE_KEY + 1)]
maxCountsComps = [0 for _ in range(MAX_TYPE_KEY + 1)]
minCountsLinks = [1000000000000 for _ in range(MAX_TYPE_KEY + 1)]
minCountsComps = [1000000000000 for _ in range(MAX_TYPE_KEY + 1)]
for _ in range(NUMBER_TESTS):
# some nice graph generators here: https://networkx.github.io/documentation/stable/reference/generators.html
graph = nx.fast_gnp_random_graph(TEST_SIZE, x)
# graph = nx.random_regular_graph(10, 1000)
for (u, v) in graph.edges():
graph.edges[u, v]['w'] = random.randint(1, WEIGHT_RANGE)
for heapType in TYPES.keys():
for v in graph.nodes():
graph.nodes[v]['v'] = False # "visited" marker
linkCount = 0
compCount = 0
vertex2qnode = {}
dist = [888888888 for _ in range(len(graph.nodes()))]
prev = [None for _ in range(len(graph.nodes()))]
heap = PairingHeap(heapType, COUNT_TYPE_BOTH)
heap.make_heap()
source = graph.nodes()[0]
dist[0] = 0
for idx, v in enumerate(graph.nodes()):
#qnode = Node(dist[idx])
qnode = Node(dist[v])
qnode.vertex = v
vertex2qnode[v] = qnode
(cc, lc) = heap.insert(qnode)
linkCount += lc
compCount += cc
for s in range(len(graph.nodes())):
(minNode, cc, lc) = heap.delete_min()
linkCount += lc
compCount += cc
if minNode is None:
raise Exception(
"delete-min on heap of type {} returned None with {} nodes removed".format(TYPES[heapType],
s))
u = minNode.vertex
uk = minNode.key
#print(uk)
#print('extracted {}'.format(minNode.key))
graph.nodes[u]['v'] = True # minNode has been visited
for idx, v in enumerate(graph.neighbors(u)):
alt = uk + graph.edges[u, v]['w']
if alt < dist[v] and not graph.nodes[v]['v']:
(cc, lc) = heap.decrease_key(vertex2qnode[v], dist[v] - alt)
#print('decreased from {} to {}'.format(dist[v],alt))
linkCount += lc
compCount += cc
dist[v] = alt
prev[v] = u
avgCountsLinks[heapType] += (linkCount / NUMBER_TESTS)/TEST_SIZE
avgCountsComps[heapType] += (compCount / NUMBER_TESTS)/TEST_SIZE
maxCountsLinks[heapType] = max(maxCountsLinks[heapType],linkCount/TEST_SIZE)
maxCountsComps[heapType] = max(maxCountsComps[heapType],compCount/TEST_SIZE)
minCountsLinks[heapType] = min(minCountsLinks[heapType],linkCount/TEST_SIZE)
minCountsComps[heapType] = min(minCountsComps[heapType],compCount/TEST_SIZE)
for heapType in TYPES.keys():
pid = os.getpid()
py = psutil.Process(pid)
memoryUse = py.memory_info()[0] / 2. ** 30 # memory use in GB
print(
"[{}] \t avgComp: {} \t avgLink: {} \t RAM: {} \t |V|={} \t |E|={}".format(
TYPES[heapType], avgCountsComps[heapType], avgCountsLinks[heapType], memoryUse, len(graph.nodes()), len(graph.edges())))
avgLinksPerSize += [avgCountsLinks]
avgCompsPerSize += [avgCountsComps]
maxLinksPerSize += [maxCountsLinks]
maxCompsPerSize += [maxCountsComps]
minLinksPerSize += [minCountsLinks]
minCompsPerSize += [minCountsComps]
# plot_avg_counts([avgCompsPerSize, avgLinksPerSize])
plot_avg_counts([avgCompsPerSize, avgLinksPerSize, maxCompsPerSize, maxLinksPerSize, minCompsPerSize, minLinksPerSize])
export_results(xs, [avgCompsPerSize, avgLinksPerSize], COUNT_TYPE_BOTH, TYPES, "dijkstra")
#!/usr/bin/python3
from node import Node
from pairing_heap_interface import PairingHeapInterface
from pairing_heap import PairingHeap
import networkx as nx
import sys
import random
import math
import numpy as np
import matplotlib.pyplot as plt
import os
import psutil
import csv
COUNT_TYPE_BOTH = 0
COUNT_TYPE_LINKS = -1
COUNT_TYPE_COMPS = -2
TYPES = {21: "Pairing", 22: "Smooth"}
MAX_TYPE_KEY = max(TYPES.keys())
#COLOURS = ['xkcd:fire engine red', 'xkcd:dusty orange', 'xkcd:clear blue', 'xkcd:cool green',
# 'xkcd:macaroni and cheese', 'xkcd:fire engine red', 'xkcd:dusty orange', 'xkcd:clear blue',
# 'xkcd:cool green', 'xkcd:macaroni and cheese', 'xkcd:bright sky blue', 'xkcd:bright sky blue', 'xkcd:green',
# 'xkcd:ochre', 'xkcd:sea blue', 'xkcd:sea green', 'xkcd:sea blue', 'xkcd:warm grey',
# 'xkcd:bright sky blue', 'xkcd:bright sky blue']
LINETYPES = 5 * ['-'] + 5 * ['--'] + ['--', '-'] + ['--', '--', '--', '--', '--', '--', '-', '-']
FIG_LABELS = ["comparisons", "links"]
MAX_TYPE_KEY = max(TYPES.keys())
COLOURS = {21:'xkcd:fire engine red', 22:'xkcd:sea green'}
SHADE_COLOURS = {21:'#fe4d4e', 22:'#58ab8e'}
NUMBER_TESTS = 10 # number of tests to run
TEST_SIZE = 500 # ,6000,7000,8000,9000,10000,20000,30000,40000,50000,60000,70000,80000,90000,100000
EDGE_PROBABILITY = 0.05
WEIGHT_RANGE = 10000
def plot_avg_counts_old(avgCounts):
# colours from https://xkcd.com/color/rgb/
linetypes = 5 * ["-"] + 5 * ["--"] + ["--", "-"] + ["-, -"]
plt.figure('Dijkstra with variable connectivity')
for k in TYPES.keys():
avgComps = [acounts[k] for acounts in avgCounts[0]]
plt.plot([factor * EDGE_PROBABILITY for factor in range(1, 101, 1)], avgComps, color=COLOURS[k], linestyle='-',
label=TYPES[k] + " comparisons")
avgLinks = [acounts[k] for acounts in avgCounts[1]]
plt.plot([factor * EDGE_PROBABILITY for factor in range(1, 101, 1)], avgLinks, color=COLOURS[k], linestyle='--',
label=TYPES[k] + " links")
plt.grid(True)
plt.legend(loc='best')
plt.show()
def plot_avg_counts(avgCounts):
# colours from https://xkcd.com/color/rgb/
MARKERS_COMP = {21:"o", 12:"d", 22:"^"}#https://matplotlib.org/3.1.1/api/markers_api.html
MARKERS_LINK = {21:"o", 12:"D", 22:"D"}
plt.figure('avg number of operations in Dijkstra\'s algorithm')
deviations = [ 10+round(TEST_SIZE*20*factor * EDGE_PROBABILITY) for factor in range(1, 21, 1)]
for k in TYPES.keys():
#print(k)
avgComps = [acounts[k] for acounts in avgCounts[0]]
maxComps = [acounts[k] for acounts in avgCounts[2]]
minComps = [acounts[k] for acounts in avgCounts[4]]
plt.plot(deviations, avgComps, color=COLOURS[k], linestyle="-", marker=MARKERS_COMP[k], markerfacecolor=COLOURS[k], markersize=9, markeredgewidth=1, markeredgecolor='black', label=TYPES[k] + " comparisons")
plt.fill_between(deviations, minComps, maxComps, color=SHADE_COLOURS[k], alpha=.3)
avgLinks = [acounts[k] for acounts in avgCounts[1]]
maxLinks = [acounts[k] for acounts in avgCounts[3]]
minLinks = [acounts[k] for acounts in avgCounts[5]]
plt.plot(deviations, avgLinks, color=COLOURS[k], linestyle="--", marker=MARKERS_LINK[k], markerfacecolor=COLOURS[k], markersize=9, markeredgewidth=1, markeredgecolor='black', label=TYPES[k] + " links")
plt.fill_between(deviations, minLinks, maxLinks, color=SHADE_COLOURS[k], alpha=.3)
plt.xlabel('Graph size', fontsize=26)
plt.ylabel('Avg. number of operations / size', fontsize=26)
plt.xticks(fontsize=20)
plt.yticks(fontsize=20)
plt.rc('legend',fontsize=26) # using a size in points
plt.legend()
plt.grid(True)
#plt.gca().invert_xaxis()
figure = plt.gcf() # get current figure
figure.set_size_inches(16, 18) # set figure's size manually to full screen
plt.savefig('plots/paper-dijkstra2-new.svg', bbox_inches='tight') # bbox_inches removes extra white spaces
plt.legend(loc='best')
plt.show()
def export_results(xs, results, countType, heapTypes, filename="dijkstra2"):
# parse data as randomness parameter; counts per heap type
if countType == COUNT_TYPE_BOTH:
with open("data/" + filename + '-comps.csv', 'w', newline='') as csvfile:
csvwriter = csv.writer(csvfile, delimiter=';', quotechar='|', quoting=csv.QUOTE_MINIMAL)
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.values()])
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.keys()])
for i in range(len(results[0])):
row = [xs[i]] + [results[0][i][k] for k in TYPES.keys()]
csvwriter.writerow(row)
with open("data/" + filename + '-links.csv', 'w', newline='') as csvfile:
csvwriter = csv.writer(csvfile, delimiter=';', quotechar='|', quoting=csv.QUOTE_MINIMAL)
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.values()])
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.keys()])
for i in range(len(results[1])):
row = [xs[i]] + [results[1][i][k] for k in TYPES.keys()]
csvwriter.writerow(row)
else:
fn = "data/" + filename + '-links.csv' if countType == COUNT_TYPE_LINKS else "data/" + filename + '-comps.csv'
with open(fn, 'w', newline='') as csvfile:
csvwriter = csv.writer(csvfile, delimiter=';', quotechar='|', quoting=csv.QUOTE_MINIMAL)
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.values()])
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.keys()])
for i in range(len(results)):
row = [xs[i]]+[results[i][k] for k in TYPES.keys()]
csvwriter.writerow(row)
if __name__ == "__main__":
testOutputCount = []
avgLinksPerSize = []
avgCompsPerSize = []
maxLinksPerSize = []
maxCompsPerSize = []
minLinksPerSize = []
minCompsPerSize = []
xs = [factor * EDGE_PROBABILITY for factor in range(1, 21, 1)]
for x in xs:
avgCountsLinks = [0 for _ in range(MAX_TYPE_KEY + 1)]
avgCountsComps = [0 for _ in range(MAX_TYPE_KEY + 1)]
maxCountsLinks = [0 for _ in range(MAX_TYPE_KEY + 1)]
maxCountsComps = [0 for _ in range(MAX_TYPE_KEY + 1)]
minCountsLinks = [1000000000000 for _ in range(MAX_TYPE_KEY + 1)]
minCountsComps = [1000000000000 for _ in range(MAX_TYPE_KEY + 1)]
for _ in range(NUMBER_TESTS):
# some nice graph generators here: https://networkx.github.io/documentation/stable/reference/generators.html
##graph = nx.fast_gnp_random_graph(100, 0.1)
graph = nx.random_regular_graph(10,10+round(TEST_SIZE*x*20))
##graph = nx.random_regular_graph(10,100)
for (u, v) in graph.edges():
graph.edges[u, v]['w'] = random.randint(1, WEIGHT_RANGE)
for heapType in TYPES.keys():
#print('---')
for v in graph.nodes():
graph.nodes[v]['v'] = False # "visited" marker
linkCount = 0
compCount = 0
vertex2qnode = {}
dist = [888888888 for _ in range(len(graph.nodes()))]
prev = [None for _ in range(len(graph.nodes()))]
heap = PairingHeap(heapType, COUNT_TYPE_BOTH)
heap.make_heap()
source = graph.nodes()[0]
dist[0] = 0
for idx, v in enumerate(graph.nodes()):
# qnode = Node(dist[idx])
qnode = Node(dist[v])
qnode.vertex = v
vertex2qnode[v] = qnode
(cc, lc) = heap.insert(qnode)
#print('inserted key {}',qnode.key)
linkCount += lc
compCount += cc
for s in range(len(graph.nodes())):
(minNode, cc, lc) = heap.delete_min()
linkCount += lc
compCount += cc
if minNode is None:
raise Exception(
"delete-min on heap of type {} returned None with {} nodes removed".format(TYPES[heapType],
s))
u = minNode.vertex
uk = minNode.key
#print(uk)
#print('extracted {}'.format(minNode.key))
graph.nodes[u]['v'] = True # minNode has been visited
for idx, v in enumerate(graph.neighbors(u)):
alt = uk + graph.edges[u, v]['w']
if alt < dist[v] and not graph.nodes[v]['v']:
(cc, lc) = heap.decrease_key(vertex2qnode[v], dist[v] - alt)
#print('decreased from {} to {}'.format(dist[v],alt))
linkCount += lc
compCount += cc
dist[v] = alt
prev[v] = u
TSIZE = 10+round(TEST_SIZE*x*20)
avgCountsLinks[heapType] += (linkCount / NUMBER_TESTS)/TSIZE
avgCountsComps[heapType] += (compCount / NUMBER_TESTS)/TSIZE
maxCountsLinks[heapType] = max(maxCountsLinks[heapType],linkCount/TSIZE)
maxCountsComps[heapType] = max(maxCountsComps[heapType],compCount/TSIZE)
minCountsLinks[heapType] = min(minCountsLinks[heapType],linkCount/TSIZE)
minCountsComps[heapType] = min(minCountsComps[heapType],compCount/TSIZE)
for heapType in TYPES.keys():
pid = os.getpid()
py = psutil.Process(pid)
memoryUse = py.memory_info()[0] / 2. ** 30 # memory use in GB
print(
"[{}] \t avgComp: {} \t avgLink: {} \t RAM: {} \t |V|={} \t |E|={}".format(
TYPES[heapType], avgCountsComps[heapType], avgCountsLinks[heapType], memoryUse, len(graph.nodes()), len(graph.edges())))
avgLinksPerSize += [avgCountsLinks]
avgCompsPerSize += [avgCountsComps]
maxLinksPerSize += [maxCountsLinks]
maxCompsPerSize += [maxCountsComps]
minLinksPerSize += [minCountsLinks]
minCompsPerSize += [minCountsComps]
# plot_avg_counts([avgCompsPerSize, avgLinksPerSize])
plot_avg_counts([avgCompsPerSize, avgLinksPerSize, maxCompsPerSize, maxLinksPerSize, minCompsPerSize, minLinksPerSize])
export_results(xs, [avgCompsPerSize, avgLinksPerSize], COUNT_TYPE_BOTH, TYPES, "dijkstra")
#!/usr/bin/python3
import random
import copy
import matplotlib.pyplot as plt
import math
import numpy as np
"""This file generates visualizations of the different random permutation classes"""
def plot_permutation(permutation, title, filename):
# visualizing given permutation as element index in permutation over element index in sorted list
# colours from https://xkcd.com/color/rgb/
plt.figure(title)
sortedList = copy.copy(permutation)
sortedList.sort()
indices = [i for i in range(len(sortedList))]
pindices = [permutation.index(x) for x in sortedList]
plt.plot(indices, pindices, color='xkcd:charcoal', marker='o', linestyle="", label="(sorted index, permuted index)")
plt.xlabel('Index in sorted list', fontsize=26)
plt.ylabel('Index in permutation', fontsize=26)
plt.xticks(fontsize=20)
plt.yticks(fontsize=20)
plt.rc('legend',fontsize=26) # using a size in points
plt.legend()
plt.grid(True)
figure = plt.gcf() # get current figure
figure.set_size_inches(16, 18) # set figure's size manually to full screen
plt.savefig('plots/paper-permutation-{}.svg'.format(filename), bbox_inches='tight') # bbox_inches removes extra white spaces
plt.legend(loc='best')
plt.show()
def localizedShuffleByIndex(llist, sdev):
tuples = []
for element in llist:
key = np.random.normal(llist.index(element) * 1.0 / len(llist),
sdev) # generate key using gaussian distribution over sorted index
tuples += [(key, element)] # store element with key
sortedTuples = sorted(tuples, key=lambda x: x[0]) # sort key-element tuples by keys
sortedList = [tup[1] for tup in sortedTuples] # discard keys
return sortedList
def separablePermutation(n):
assert (n & (n - 1) == 0) and n != 0 and n > 1, "n must be a power of two > 1" # bit magic
def generateSepPermutation(l, r):
flip = random.random() >= 0.5
if r - l == 1:
if flip == 0:
return [r, l]
else:
return [l, r]
else:
m = math.floor((l + r) / 2)
if flip == 0:
return generateSepPermutation(m + 1, r) + generateSepPermutation(l, m)
else:
return generateSepPermutation(l, m) + generateSepPermutation(m + 1, r)
return generateSepPermutation(0, n - 1)
def generateContSortedSubseq(llist, sublen):
listcopy = copy.copy(llist)
random.shuffle(listcopy)
res = []
l = 0
while l < len(llist):
clen = random.randint(1, sublen)
# clen = sublen
sublist = copy.copy(listcopy[l:min(l + clen, len(listcopy))])
sublist.sort()
res += sublist
l += clen
return res
sortedList = [x for x in range(512)]
# generating uniformly random permutation
randomPermutation = copy.copy(sortedList)
random.shuffle(randomPermutation)
plot_permutation(randomPermutation, "Uniformly Random Permutation", "uniform")
# generating random separable permutation
separablePermutation = separablePermutation(512)
plot_permutation(separablePermutation, "Random Separable Permutation", "separable")
# generating random localized permutation
localizedPermutation = localizedShuffleByIndex(sortedList, 0.15)
plot_permutation(localizedPermutation, "Random Localized Permutation", "localized")
# generating random permutation with continuous sorted subsequences
subseqPermutation = generateContSortedSubseq(sortedList, 30)
plot_permutation(subseqPermutation, "Random Subsequence Permutation", "subseq")
#!/usr/bin/python3
from random import shuffle
import random
import numpy as np
import matplotlib.pyplot as plt
import sys
import signal
import copy
import math
import csv
from node import Node
from pairing_heap import PairingHeap
COUNT_TYPE_BOTH = 0
COUNT_TYPE_LINKS = -1
COUNT_TYPE_COMPS = -2
MAXSIZE = 17
NUMBER_TESTS = 10 # number of tests to run
TEST_SIZES = [j for j in range(MAXSIZE)]
LIST_LEN = 10000 # number of elements in test list
TEST_SIZE = 10000 # number of elements in test list
STEP_SIZE = 100
INCREMENT_LOC = 0.01
INCREMENT_SUBSEQS = 100
TYPES = {0: "Pairing", 12: "Smooth"}
MAX_TYPE_KEY = max(TYPES.keys())
COLOURS = {0:'xkcd:fire engine red', 12:'xkcd:green'}
SHADE_COLOURS = {0:'#fe4d4e', 12:'#58ab8e'}
def isSorted(list0):
return all(list0[i] < list0[i + 1] for i in range(len(list0) - 1))
def localizedShuffleByIndex(llist, sdev):
tuples = []
for element in llist:
key = np.random.normal(llist.index(element) * 1.0 / len(llist),
sdev) # generate key using gaussian distribution over sorted index
tuples += [(key, element)] # store element with key
sortedTuples = sorted(tuples, key=lambda x: x[0]) # sort key-element tuples by keys
sortedList = [tup[1] for tup in sortedTuples] # discard keys
# print(sortedList)
return sortedList
def plot_avg_counts(avgCounts):
# colours from https://xkcd.com/color/rgb/
MARKERS_COMP = {0:"o", 12:"^"}#https://matplotlib.org/3.1.1/api/markers_api.html
MARKERS_LINK = {0:"o", 12:"D"}
plt.figure('avg number of operations by heap type')
deviations = [fac * INCREMENT_LOC for fac in range(0, math.ceil(0.3 / INCREMENT_LOC), 1)]
for k in TYPES.keys():
#print(k)
avgComps = [acounts[k] for acounts in avgCounts[0]]
maxComps = [acounts[k] for acounts in avgCounts[2]]
minComps = [acounts[k] for acounts in avgCounts[4]]
plt.plot(deviations, avgComps, color=COLOURS[k], linestyle="-", marker=MARKERS_COMP[k], markerfacecolor=COLOURS[k], markersize=9, markeredgewidth=1, markeredgecolor='black', label=TYPES[k] + " comparisons")
plt.fill_between(deviations, minComps, maxComps, color=SHADE_COLOURS[k], alpha=.3)
avgLinks = [acounts[k] for acounts in avgCounts[1]]
maxLinks = [acounts[k] for acounts in avgCounts[3]]
minLinks = [acounts[k] for acounts in avgCounts[5]]
plt.plot(deviations, avgLinks, color=COLOURS[k], linestyle="--", marker=MARKERS_LINK[k], markerfacecolor=COLOURS[k], markersize=9, markeredgewidth=1, markeredgecolor='black', label=TYPES[k] + " links")
plt.fill_between(deviations, minLinks, maxLinks, color=SHADE_COLOURS[k], alpha=.3)
#plt.title('Sorting random separable permutations', fontsize=25)
plt.xlabel('Locality parameter', fontsize=26)
plt.ylabel('Avg. number of operations / size', fontsize=26)
plt.xticks(fontsize=20)
plt.yticks(fontsize=20)
plt.rc('legend',fontsize=26) # using a size in points
plt.legend()
plt.grid(True)
figure = plt.gcf() # get current figure
figure.set_size_inches(16, 18) # set figure's size manually to your full screen (32x18)
plt.savefig('plots/paper-sorting-loc-new.svg', bbox_inches='tight') # bbox_inches removes extra white spaces
plt.legend(loc='best')
plt.show()
def export_results(params, results, countType, heapTypes, filename="dijkstra"):
# exports results of simulation as separate .csv files, one for links and one for comparisons, into /data directory
# each row contains randomness parameter value; plus one column containing the number of operations for each heap type
if countType == COUNT_TYPE_BOTH:
with open("data/" + filename + '-comps.csv', 'w', newline='') as csvfile:
csvwriter = csv.writer(csvfile, delimiter=';', quotechar='|', quoting=csv.QUOTE_MINIMAL)
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.values()])
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.keys()])
for i in range(len(results[0])):
row = [params[i]] + [results[0][i][k] for k in TYPES.keys()]
csvwriter.writerow(row)
with open("data/" + filename + '-links.csv', 'w', newline='') as csvfile:
csvwriter = csv.writer(csvfile, delimiter=';', quotechar='|', quoting=csv.QUOTE_MINIMAL)
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.values()])
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.keys()])
for i in range(len(results[1])):
row = [params[i]] + [results[1][i][k] for k in TYPES.keys()]
csvwriter.writerow(row)
else:
fn = "data/" + filename + '-links.csv' if countType == COUNT_TYPE_LINKS else "data/" + filename + '-comps.csv'
with open(fn, 'w', newline='') as csvfile:
csvwriter = csv.writer(csvfile, delimiter=';', quotechar='|', quoting=csv.QUOTE_MINIMAL)
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.values()])
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.keys()])
for i in range(len(results)):
row = [params[i]] + [results[i][k] for k in TYPES.keys()]
csvwriter.writerow(row)
if __name__ == "__main__":
testOutputCount = []
avgLinksPerSize = []
avgCompsPerSize = []
maxLinksPerSize = []
maxCompsPerSize = []
minLinksPerSize = []
minCompsPerSize = []
sortedInput = []
#testInput = []
# ----------localised permutation inputs--------------
# randomness parameter: standard deviation
params = [fac * INCREMENT_LOC+0.00001 for fac in range(0, math.ceil(0.3 / INCREMENT_LOC), 1)]
for x in params:
sortedInput = [k for k in range(10000)]
avgCountsLinks = [0 for _ in range(MAX_TYPE_KEY + 1)]
avgCountsComps = [0 for _ in range(MAX_TYPE_KEY + 1)]
maxCountsLinks = [0 for _ in range(MAX_TYPE_KEY + 1)]
maxCountsComps = [0 for _ in range(MAX_TYPE_KEY + 1)]
minCountsLinks = [1000000000000 for _ in range(MAX_TYPE_KEY + 1)]
minCountsComps = [1000000000000 for _ in range(MAX_TYPE_KEY + 1)]
for zz in range(NUMBER_TESTS):
testInput = localizedShuffleByIndex(sortedInput, x)
print(len(testInput))
for heapType in TYPES.keys():
linkCount = 0
compCount = 0
testOutput = []
heap = PairingHeap(heapType, COUNT_TYPE_BOTH)
heap.make_heap()
for element in testInput:
node = Node(element)
(cc, lc) = heap.insert(node)
for i in range(len(testInput)):
(minNode, cc, lc) = heap.delete_min()
testOutput += [minNode.key]
compCount += cc
linkCount += lc
if isSorted(testOutput): # sanity check
#divide by size for visualization
avgCountsLinks[heapType] += (linkCount/10000) / NUMBER_TESTS
avgCountsComps[heapType] += (compCount/10000) / NUMBER_TESTS
maxCountsLinks[heapType] = max(maxCountsLinks[heapType],linkCount/10000)
maxCountsComps[heapType] = max(maxCountsComps[heapType],compCount/10000)
minCountsLinks[heapType] = min(minCountsLinks[heapType],linkCount/10000)
minCountsComps[heapType] = min(minCountsComps[heapType],compCount/10000)
else:
raise Exception("Invalid result for {}".format(TYPES[heapType]))
print("[{}: {}, {}/{}] \t Links: {} \t Comps: {}".format(
TYPES[heapType], x, zz+1, NUMBER_TESTS, linkCount, compCount))# diagnostics
for heapType in TYPES.keys():
print("[{}: {}, avg] \t Links: {} \t Comps: {}".format(TYPES[heapType], x, avgCountsLinks[heapType], avgCountsComps[heapType]))
avgLinksPerSize += [avgCountsLinks]
avgCompsPerSize += [avgCountsComps]
maxLinksPerSize += [maxCountsLinks]
maxCompsPerSize += [maxCountsComps]
minLinksPerSize += [minCountsLinks]
minCompsPerSize += [minCountsComps]
plot_avg_counts([avgCompsPerSize, avgLinksPerSize, maxCompsPerSize, maxLinksPerSize, minCompsPerSize, minLinksPerSize])
export_results(params, [avgCompsPerSize, avgLinksPerSize], COUNT_TYPE_BOTH, TYPES, "sorting-loc-new")
#!/usr/bin/python3
from random import shuffle
import random
import numpy as np
import matplotlib.pyplot as plt
import sys
import signal
import copy
import math
import csv
from node import Node
from pairing_heap import PairingHeap
COUNT_TYPE_BOTH = 0
COUNT_TYPE_LINKS = -1
COUNT_TYPE_COMPS = -2
MAXSIZE = 18
NUMBER_TESTS = 20 # number of tests to run
TEST_SIZES = [j for j in range(MAXSIZE)]
LIST_LEN = 10000 # number of elements in test list
TEST_SIZE = 10000 # number of elements in test list
STEP_SIZE = 100
INCREMENT_LOC = 0.005
INCREMENT_SUBSEQS = 100
TYPES = {0: "Pairing", 12: "Smooth"}
MAX_TYPE_KEY = max(TYPES.keys())
COLOURS = {0:'xkcd:fire engine red', 12:'xkcd:green'}
SHADE_COLOURS = {0:'#fe4d4e', 12:'#58ab8e'}
def isSorted(list0):
return all(list0[i] < list0[i + 1] for i in range(len(list0) - 1))
def plot_avg_counts(avgCounts):
# colours from https://xkcd.com/color/rgb/
MARKERS_COMP = {0:"o", 12:"^"}#https://matplotlib.org/3.1.1/api/markers_api.html
MARKERS_LINK = {0:"o", 12:"D"}
plt.figure('avg number of operations by heap type')
for k in TYPES.keys():
print(k)
avgComps = [acounts[k] for acounts in avgCounts[0]]
maxComps = [acounts[k] for acounts in avgCounts[2]]
minComps = [acounts[k] for acounts in avgCounts[4]]
plt.plot([2**p for p in range(4, MAXSIZE)], avgComps[3:MAXSIZE-1], color=COLOURS[k], linestyle="-", marker=MARKERS_COMP[k], markerfacecolor=COLOURS[k], markersize=9, markeredgewidth=1, markeredgecolor='black', label=TYPES[k] + " comparisons")
plt.fill_between([2**p for p in range(4, MAXSIZE)], minComps[3:MAXSIZE-1], maxComps[3:MAXSIZE-1], color=SHADE_COLOURS[k], alpha=.3)
avgLinks = [acounts[k] for acounts in avgCounts[1]]
maxLinks = [acounts[k] for acounts in avgCounts[3]]
minLinks = [acounts[k] for acounts in avgCounts[5]]
plt.plot([2**p for p in range(4, MAXSIZE)], avgLinks[3:MAXSIZE-1], color=COLOURS[k], linestyle="--", marker=MARKERS_LINK[k], markerfacecolor=COLOURS[k], markersize=9, markeredgewidth=1, markeredgecolor='black', label=TYPES[k] + " links")
plt.fill_between([2**p for p in range(4, MAXSIZE)], minLinks[3:MAXSIZE-1], maxLinks[3:MAXSIZE-1], color=SHADE_COLOURS[k], alpha=.3)
#plt.title('Sorting random separable permutations', fontsize=25)
plt.xlabel('Input size', fontsize=26)
plt.ylabel('Avg. number of operations / size', fontsize=26)
plt.xticks(fontsize=20)
plt.yticks(fontsize=20)
plt.rc('legend',fontsize=26) # using a size in points
plt.legend()
plt.grid(True)
figure = plt.gcf() # get current figure
figure.set_size_inches(16, 18) # set figure's size manually to full screen
plt.savefig('plots/paper-sorting-sep-new.svg', bbox_inches='tight') # bbox_inches removes extra white spaces
plt.legend(loc='best')
plt.show()
def export_results(params, results, countType, heapTypes, filename="dijkstra"):
# exports results of simulation as separate .csv files, one for links and one for comparisons, into /data directory
# each row contains randomness parameter value; plus one column containing the number of operations for each heap type
if countType == COUNT_TYPE_BOTH:
with open("data/" + filename + '-comps.csv', 'w', newline='') as csvfile:
csvwriter = csv.writer(csvfile, delimiter=';', quotechar='|', quoting=csv.QUOTE_MINIMAL)
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.values()])
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.keys()])
for i in range(len(results[0])):
row = [params[i]] + [results[0][i][k] for k in TYPES.keys()]
csvwriter.writerow(row)
with open("data/" + filename + '-links.csv', 'w', newline='') as csvfile:
csvwriter = csv.writer(csvfile, delimiter=';', quotechar='|', quoting=csv.QUOTE_MINIMAL)
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.values()])
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.keys()])
for i in range(len(results[1])):
row = [params[i]] + [results[1][i][k] for k in TYPES.keys()]
csvwriter.writerow(row)
else:
fn = "data/" + filename + '-links.csv' if countType == COUNT_TYPE_LINKS else "data/" + filename + '-comps.csv'
with open(fn, 'w', newline='') as csvfile:
csvwriter = csv.writer(csvfile, delimiter=';', quotechar='|', quoting=csv.QUOTE_MINIMAL)
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.values()])
csvwriter.writerow(["randomness parameter value"] + [name for name in TYPES.keys()])
for i in range(len(results)):
row = [params[i]] + [results[i][k] for k in TYPES.keys()]
csvwriter.writerow(row)
def separablePermutation(n):
assert (n & (n - 1) == 0) and n != 0 and n > 1, "n must be a power of two > 1" # bit magic
def generateSepPermutation(l, r):
flip = random.random() >= 0.5
if r - l == 1:
if flip == 0:
return [r, l]
else:
return [l, r]
else:
m = math.floor((l + r) / 2)
if flip == 0:
return generateSepPermutation(m + 1, r) + generateSepPermutation(l, m)
else:
return generateSepPermutation(l, m) + generateSepPermutation(m + 1, r)
return generateSepPermutation(0, n - 1)
if __name__ == "__main__":
testOutputCount = []
avgLinksPerSize = []
avgCompsPerSize = []
maxLinksPerSize = []
maxCompsPerSize = []
minLinksPerSize = []
minCompsPerSize = []
sortedInput = []
# testInput = []
# ----------separable permutation---------------------
# parameter: length (must be power of two)
params = [2**p for p in range(1, MAXSIZE)]
for x in params:
sortedInput = [k for k in range(x)]
avgCountsLinks = [0 for _ in range(MAX_TYPE_KEY + 1)]
avgCountsComps = [0 for _ in range(MAX_TYPE_KEY + 1)]
maxCountsLinks = [0 for _ in range(MAX_TYPE_KEY + 1)]
maxCountsComps = [0 for _ in range(MAX_TYPE_KEY + 1)]
minCountsLinks = [1000000000000 for _ in range(MAX_TYPE_KEY + 1)]
minCountsComps = [1000000000000 for _ in range(MAX_TYPE_KEY + 1)]
for zz in range(NUMBER_TESTS):
testInput = copy.copy(sortedInput)
testInput = separablePermutation(x)
testInput[0] = -1
for heapType in TYPES.keys():
linkCount = 0
compCount = 0
testOutput = []
heap = PairingHeap(heapType, COUNT_TYPE_BOTH)
heap.make_heap()
for element in testInput:
node = Node(element)
(cc, lc) = heap.insert(node)
for i in range(len(testInput)):
(minNode, cc, lc) = heap.delete_min()
testOutput += [minNode.key]
compCount += cc
linkCount += lc
if isSorted(testOutput): # sanity check
#divide by size for visualization
avgCountsLinks[heapType] += (linkCount/x) / NUMBER_TESTS
avgCountsComps[heapType] += (compCount/x) / NUMBER_TESTS
maxCountsLinks[heapType] = max(maxCountsLinks[heapType],linkCount/x)
maxCountsComps[heapType] = max(maxCountsComps[heapType],compCount/x)
minCountsLinks[heapType] = min(minCountsLinks[heapType],linkCount/x)
minCountsComps[heapType] = min(minCountsComps[heapType],compCount/x)
else:
raise Exception("Invalid result for {}".format(TYPES[heapType]))
print("[{}: {}, {}/{}] \t Links: {} \t Comps: {}".format(
TYPES[heapType], x, zz+1, NUMBER_TESTS, linkCount, compCount))
for heapType in TYPES.keys():
print("[{}: {}, avg] \t Links: {} \t Comps: {}".format(TYPES[heapType], x, avgCountsLinks[heapType], avgCountsComps[heapType]))
avgLinksPerSize += [avgCountsLinks]
avgCompsPerSize += [avgCountsComps]
maxLinksPerSize += [maxCountsLinks]
maxCompsPerSize += [maxCountsComps]
minLinksPerSize += [minCountsLinks]
minCompsPerSize += [minCountsComps]
plot_avg_counts([avgCompsPerSize, avgLinksPerSize, maxCompsPerSize, maxLinksPerSize, minCompsPerSize, minLinksPerSize])
export_results(params, [avgCompsPerSize, avgLinksPerSize], COUNT_TYPE_BOTH, TYPES, "sorting-sep-new")
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment