._site

(Arne Babenhauserheide)
2012-07-26: more optimization options and nicer plots (which only work if you

more optimization options and nicer plots (which only work if you convert and compile pylab/matplotlib by hand right now).

diff --git a/sim.py b/sim.py
--- a/sim.py
+++ b/sim.py
@@ -243,7 +243,7 @@ def checkjump(target, prev, net):
         return True
 
 def checkswitch(target, prev, net):
-    """Check if we should jump to the target.
+    """Check if we should switch positions with the target.
 
     :param targetdeviation: deviation of the link distribution at the
         target from a small world distribution."""
@@ -252,6 +252,23 @@ def checkswitch(target, prev, net):
             switchwithtarget(target, prev, net)
             return True
 
+def checkswitchalways(target, prev, net):
+    """Always switch positions with the target.
+
+    :param targetdeviation: deviation of the link distribution at the
+        target from a small world distribution."""
+    switchwithtarget(target, prev, net)
+    return True
+
+def checkswitchonesided(target, prev, net):
+    """Always switch positions with the target.
+
+    :param targetdeviation: deviation of the link distribution at the
+        target from a small world distribution."""
+    if hasbetterlinks(target, prev, net):
+        switchwithtarget(target, prev, net)
+        return True
+
 def checkjumphalf(target, prev, net):
     """Check if we should jump halfway to the target.
 
@@ -267,6 +284,35 @@ def checkjumphalf(target, prev, net):
         jumptotarget(target, prev, net)
         return True
 
+def checkjumpratio(target, prev, net, ratio):
+    """Check if we should jump to the given ratio between prev and
+    target.
+
+    :param targetdeviation: deviation of the link distribution at the
+        target from a small world distribution."""
+    conns = net[prev][:]
+    target = prev * (1-ratio) + target * ratio
+    old = distances(prev, conns)
+    new = distances(target, conns)
+    newdev = deviationfromsmallworld(new)
+    olddev = deviationfromsmallworld(old)
+    if sum(newdev) < sum(olddev):
+        jumptotarget(target, prev, net)
+        return True
+
+def checkjumpgolden(target, prev, net, small=False):
+    """Check if we should jump the small or large golden ratio
+    (√5-1)/2 to the target (small=closer to the prev, not small=closer
+    to the target).
+
+    :param targetdeviation: deviation of the link distribution at the
+        target from a small world distribution."""
+    golden = (math.sqrt(5)-1)/2.0
+    if small:
+        return checkjumpratio(target, prev, net, 1-golden)
+    else:
+        return checkjumpratio(target, prev, net, golden)
+
 def checkconnect(target, prev, net):
     """Check if we should connect to the target.
 
@@ -350,7 +396,7 @@ def checkreplacelongest(target, prev, ne
         disconnectfromtarget(tokillconn, prev, net)
     return True
 
-def checkfold(target, prev, net, probability=0.2, strategy="jumphalf"):
+def checkfold(target, prev, net, probability=0.07, strategy="jumphalf"):
     """switch to the target location with some probability"""
     if random() > probability:
         return
@@ -358,8 +404,16 @@ def checkfold(target, prev, net, probabi
         return checkjump(target, prev, net)
     if strategy == "switch":
         return checkswitch(target, prev, net)
+    if strategy == "switchalways":
+        return checkswitchalways(target, prev, net)
+    if strategy == "switchonesided":
+        return checkswitchonesided(target, prev, net)
     if strategy == "jumphalf":
         return checkjumphalf(target, prev, net)
+    if strategy == "jumpgolden":
+        return checkjumpgolden(target, prev, net)
+    if strategy == "jumpgoldensmall":
+        return checkjumpgolden(target, prev, net, small=True)
     if strategy == "connect":
         return checkconnect(target, prev, net)
     if strategy == "replacebest":
@@ -405,11 +459,11 @@ def linklengths(net):
 def parse_args():
     from argparse import ArgumentParser
     parser = ArgumentParser(description="Simulate Freenet network optimization.")
-    parser.add_argument("--strategy", help="The optimization strategy: jump switch jumphalf connect replacebest replacelongest connectsimple", default="jumphalf")
+    parser.add_argument("--strategy", help="The optimization strategy: switch switchalways switchonesided jump  jumphalf jumpgolden jumpgoldensmall connect connectsimple replacebest replacelongest", default="jumphalf")
     parser.add_argument("--size", help="The size of the network.", default=1000, type=int)
     parser.add_argument("--connections", help="The mean number of connections per node.", default=20, type=int)
     parser.add_argument("--maxhtl", help="The maximum length of routes to be successful.", default=20, type=int)
-    parser.add_argument("--steps", help="The maximum number of modelsteps.", default=120, type=int)
+    parser.add_argument("--steps", help="The maximum number of modelsteps.", default=60, type=int)
     parser.add_argument("--perstep", help="The number of requests to run per step.", default=100, type=int)
     parser.add_argument("-o", "--output", help="Filename of the pylab plot.", default="plot.png")
     return parser.parse_args()
@@ -417,17 +471,17 @@ def parse_args():
 if __name__ == "__main__":
     args = parse_args()
     nodes = randomnodes(args.size)
-    basenet = generatesmallworldunclean(nodes, args.connections)
     lensnapshots = {}
     foldperstep = args.perstep
-    for run in range(2):
-        if not run: 
-            net = deepcopy(basenet)
+    runs = ["ideal", "flat"]
+    for run in runs:
+        if run == "ideal": 
+            net = generatesmallworldunclean(nodes, args.connections)
         else:
             net = generateflat(nodes, args.connections)
         lensnapshots[(run,0)] = linklengths(net), [0]
-        print (np.mean(lensnapshots[(0,0)][0]))
-        print("===", "run", run, "===")
+        print (np.mean(lensnapshots[(run,0)][0]))
+        print("===", run, "===")
         routelengths = fold(net, 20)
         linklens = linklengths(net)
         print (np.mean(linklens), np.mean(routelengths), "±", np.std(routelengths), "succ", len([r for r in routelengths if r < 20])/len(routelengths), min(routelengths), max(routelengths), sum(deviationfromsmallworld(linklens, numbins=10)))
@@ -445,10 +499,11 @@ if __name__ == "__main__":
         run, i = key
         linklen, routelen = val
         # only plot one in 10 results
-        if i % 10: 
+        if i % 10 and i != 1: 
             continue
-        pl.hist(linklen, 10000, cumulative=True, normed=True, histtype='step', label=str(run) + ", " + str(i*foldperstep) + ", " + str(np.mean(routelen)))
+        succ = len([r for r in routelen if r < 20])/len(routelen)
+        pl.hist(linklen, 10000, cumulative=True, normed=True, histtype='step', label=str(run) + ", " + "{:.2f}".format(i*foldperstep) + ", len: " + "{:.2f}".format(np.mean(routelen)) + ", succ: " + "{:.2f}".format(succ))
         pl.semilogx()
-    pl.legend(loc="best")
+    pl.legend(loc="upper left")
+    pl.title(str(args.size) + " nodes, " + str(args.connections) + " connections per node, optimized with strategy " + args.strategy)
     pl.savefig(args.output)
-