Architecture present for whole sims and transcripts.

This commit is contained in:
Brandon Goodell 2018-02-08 17:04:13 -07:00
parent f51f35669a
commit 956c59ad24
17 changed files with 1210 additions and 7324 deletions

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,7 @@ class Edge(object):
''' '''
Edge object. Has an identity, some data, and a dict of nodes. Edge object. Has an identity, some data, and a dict of nodes.
''' '''
def __init__(self, params=["", {}, True]): def __init__(self, params):
try: try:
assert len(params)==3 assert len(params)==3
except AssertionError: except AssertionError:
@ -29,66 +29,11 @@ class Edge(object):
class Test_Edge(unittest.TestCase): class Test_Edge(unittest.TestCase):
def test_e(self): def test_e(self):
nellyIdent = newIdent(0) nelly = Node(params)
bill = Blockchain([], verbosity=True) milly = Node(params)
ed = Edge(params)
name = newIdent(0) ed.nodes.update({nelly.ident:nelly, milly.ident:milly})
t = time.time() self.assertEqual(len(self.nodes),2)
diff = 1.0
params = [name, t, t+1, None, diff, bill.verbose] # Genesis block has no parent, so parent = None
genesis = Block(params)
bill.addBlock(genesis)
time.sleep(10)
name = newIdent(1)
t = time.time()
diff = 1.0
params = [name, t, t+1, genesis.ident, diff, bill.verbose]
blockA = Block(params)
bill.addBlock(blockA)
# Nodes need an identity and a blockchain object and verbosity and difficulty
nelly = Node([nellyIdent, copy.deepcopy(bill), bill.verbosity, diff])
nelly.updateDifficulty(mode="Nakamoto")
time.sleep(9)
name = newIdent(len(nelly.data))
t = time.time()
params = [name, t, t+1, blockA.ident, nelly.diff, nelly.verbose]
blockB = Block(params)
nelly.updateBlockchain({blockB.ident:blockB})
time.sleep(8)
name = newIdent(len(nelly.data))
t = time.time()
params = [name, t, t+1, blockB.ident, nelly.diff, nelly.verbose]
blockC = Block(params)
nelly.updateBlockchain({blockC.ident:blockC})
time.sleep(1)
name = newIdent(len(nelly.data))
t = time.time()
params = [name, t, t+1, blockB.ident, nelly.diff, nelly.verbose] # Fork off
blockD = Block(params)
nelly.updateBlockchain({blockD.ident:blockD})
time.sleep(7)
name = newIdent(len(nelly.data))
t = time.time()
params = [name, t, t+1, blockD.ident, nelly.diff, nelly.verbose]
blockE = Block(params)
nelly.updateBlockchain({blockE.ident:blockE})
time.sleep(6)
name = newIdent(len(nelly.data))
t = time.time()
params = [name, t, t+1, blockE.ident, nelly.diff, nelly.verbose]
blockF = Block(params)
nelly.updateBlockchain({blockF.ident:blockF})
suite = unittest.TestLoader().loadTestsFromTestCase(Test_Edge) suite = unittest.TestLoader().loadTestsFromTestCase(Test_Edge)

View file

@ -1,307 +0,0 @@
import unittest, copy, random, math, time
from scipy.stats import skew
from numpy import var
from numpy import random as nprandom
#TODO: Node.data["blockchain"] != node.data
def newIdent(params):
nonce = params
# Generate new random identity.
return hash(str(nonce) + str(random.random()))
def newIntensity(params):
mode = params
if mode=="uniform":
return random.random()
def newOffset(params):
mode = params
if mode=="unifDST":
r = 2.0*random.random() - 1.0 # hours
r = 60.0*60.0*r #60 min/hr, 60 sec/min
return r
if mode=="sumOfSkellams":
# This mode uses a skellam distribution, which is
# the difference of two poisson-distributed random
# variables.
# HourOffset = skellam
# SecondOffset = skellam
# TotalOffset = 60*60*HourOffset + 60*MinuteOffset + SecondOffset
# Each skellam = poisson(1) - poisson(1)
# Reasoning: We consider most computers' local time offset from UTC
# to be a two time-scale random variable, one on the hour scale and one on
# the second scale. We make
x = nprandom.poisson(1, (2,2))
totalOffset = 60.0*60.0*float(x[0][0] - x[1][0]) + float((x[0][1] - x[1][1]))
return totalOffset
class FishGraph(StochasticProcess):
'''
Stochastic process on a graph
with the graph growing in a stochastic process too
'''
# TODO: Check if output.txt exists before beginning. If so, clear it and create a new one.
# TODO: Instead of/in addition to storing graph data in a text file, can we plot with ggplot in R?
def __init__(self, params=None, verbosity=True):
# Initialize
assert "maxTime" in params
self.maxTime = copy.deepcopy(params["maxTime"])
del params["maxTime"]
assert "numNodes" in params
numNodes = params["numNodes"]
del params["numNodes"]
self.data = params
self.t = 0.0
self.state = Graph()
self.filename = "output.txt"
self.verbose = verbosity
# Create graph
self.state.createGraph(numNodes, self.data["probEdge"], self.data["maxNeighbors"])
# Update node data
for nIdent in self.state.nodes:
n = self.state.nodes[nIdent]
difficulty = 1.0
intensity = newIntensity(params="uniform")
offset = newOffset(params="sumOfSkellams")
dat = {"intensity":intensity, "offset":offset, "blockchain":Blockchain([], verbosity=self.verbose)}
n.data.update(dat)
# Update edge data.
for eIdent in self.state.edges:
e = self.state.edges[eIdent]
e.data.update({"pendingBlocks":{}})
def go(self):
assert self.maxTime > 0.0
while self.t <= self.maxTime and len(self.state.nodes) > 0:
deltaT = self.getNextTime()
self.updateState(self.t, deltaT)
self.record()
def getNextTime(self):
# Each Poisson process event generates an exponential random variable.
# The smallest of these is selected
# The rate of the smallest determines event type.
eventTag = None
u = 0.0
while(u == 0.0):
u = copy.deepcopy(random.random())
u = -1.0*math.log(copy.deepcopy(u))/self.data["birthRate"] # Time until next stochastic birth
eventTag = "birth"
v = 0.0
while(v == 0.0):
v = copy.deepcopy(random.random())
v = -1.0*math.log(copy.deepcopy(v))/self.data["deathRate"] # Time until next stochastic death
if v < u:
u = copy.deepcopy(v)
eventTag = "death"
for nIdent in self.state.nodes:
n = self.state.nodes[nIdent] # n.ident = nIdent
v = 0.0
while(v == 0.0):
v = copy.deepcopy(random.random())
v = -1.0*math.log(copy.deepcopy(v))/n.data["intensity"]
if v < u:
u = copy.deepcopy(v)
eventTag = ["discovery", n.ident]
# Now that all the STOCHASTIC arrivals have been decided,
# We check if any of the deterministic events fire off instead.
for eIdent in self.state.edges:
e = self.state.edges[eIdent] # e.ident = eIdent
pB = e.data["pendingBlocks"]
if len(pB) > 0:
for pendingIdent in pB:
arrivalInfo = pB[pendingIdent]
v = arrivalInfo["timeOfArrival"] - self.t
if v < u and 0.0 < v:
u = copy.deepcopy(v)
eventTag = ["arrival", e.ident, pendingIdent]
deltaT = (u, eventTag)
# Formats:
# eventTag = ["arrival", e.ident, pendingIdent]
# eventTag = ["discovery", n.ident]
# eventTag = "death"
# eventTag = "birth"
return deltaT
def updateState(self, t, deltaT, mode="Nakamoto", targetRate=1.0/1209600.0):
# Depending on eventTag, update the state...
u = deltaT[0]
shout = ""
eventTag = deltaT[1]
if type(eventTag)==type("birthordeath"):
if eventTag == "death":
# Picks random nodeIdent and kills it
toDie = random.choice(list(self.state.nodes.keys()))
x = len(self.state.nodes)
shout += "DEATH, Pop(Old)=" + str(x) + ", Pop(New)="
if self.verbose:
print(shout)
self.state.delNode(toDie)
y = len(self.state.nodes)
assert y == x - 1
shout += str(y) + "\n"
elif eventTag == "birth":
# Adds node with some randomly determined edges
x = len(self.state.nodes)
shout += "BIRTH, Pop(Old)=" + str(x) + ", Pop(New)="
if self.verbose:
print(shout)
nIdent = self.state.addNode()
n = self.state.nodes[nIdent]
intensity = random.random()/1000.0
offset = 2.0*random.random() - 1.0
n.data.update({"intensity":intensity, "offset":offset, "blockchain":{}})
# Auto syncs new node.
for eIdent in n.edges:
e = n.edges[eIdent]
e.data.update({"pendingBlocks":{}})
mIdent = e.getNeighbor(n.ident)
m = self.state.nodes[mIdent]
mdata = m.data["blockchain"]
n.updateBlockchain(mdata)
y = len(self.state.nodes)
assert y == x + 1
shout += str(y) + "\n"
else:
print("Error: eventTag had length 1 but was neighter a birth or a death, this shouldn't happen so this else case will eventually be removed, I guess? Our eventTag = ", eventTag)
elif len(eventTag)==2:
# Block is discovered and plunked into each edge's pendingBlock list.
shout += "DISCOVERY\n"
if self.verbose:
print(shout)
if self.verbose:
print("Checking formation of eventTag = [\"discovery\", nodeIdent]")
assert eventTag[0]=="discovery"
assert eventTag[1] in self.state.nodes
if self.verbose:
print("Retrieving discoverer's identity")
nIdent = eventTag[1] # get founding node's identity
if self.verbose:
print("Retrieving discoverer")
n = self.state.nodes[nIdent] # get founding node
if self.verbose:
print("Computing discoverer's wall clock")
s = self.t + n.data["offset"] # get founding node's wall clock
if self.verbose:
print("Generating new block identity")
newBlockIdent = newIdent(len(n.data["blockchain"].blocks)) # generate new identity
if self.verbose:
print("Setting timestamps")
disco = s
arriv = s
if self.verbose:
print("Retrieving parent")
parent = n.data["blockchain"].miningIdent
if self.verbose:
print("getting difficulty")
diff = copy.deepcopy(n.diff)
if self.verbose:
print("setting verbosity")
verbosity = self.verbose
if self.verbose:
print("Initializing a new block")
newBlock = Block([newBlockIdent, disco, arriv, parent, diff, verbosity])
if self.verbose:
print("Updating discovering node's blockchain")
n.updateBlockchain({newBlockIdent:newBlock})
if self.verbose:
print("Computing discoverer's new difficulty")
n.updateDifficulty(mode, targetRate)
if self.verbose:
print("propagating new block.")
n.propagate(self.t, newBlockIdent)
if self.verbose:
print("discovery complete")
elif len(eventTag)==3:
#eventTag = ("arrival", e.ident, pendingIdent)
# A block deterministically arrives at the end of an edge.
assert eventTag[0]=="arrival"
shout += "ARRIVAL"
if self.verbose:
print(shout)
eIdent = eventTag[1]
pendingIdent = eventTag[2]
e = self.state.edges[eIdent]
pB = e.data["pendingBlocks"]
arrivalInfo = pB[pendingIdent] # arrivalInfo = {"timeOfArrival":toa, "destIdent":mIdent, "block":newBlock}
assert arrivalInfo["destIdent"] in self.state.nodes
assert self.t + u == arrivalInfo["timeOfArrival"]
receiver = self.state.nodes[arrivalInfo["destIdent"]]
arriv = self.t + u + receiver.data["offset"]
newBlock = arrivalInfo["block"]
newBlock.arrivTimestamp = copy.deepcopy(arriv)
receiver.updateBlockchain({newBlock.ident:newBlock})
receiver.updateDifficulty(mode, targetRate)
receiver.propagate(self.t, newBlock.ident)
else:
print("Error: eventTag was not a string, or not an array length 2 or 3. In fact, we have eventTag = ", eventTag)
if self.verbose:
print("u = ", u)
self.t += u
if self.verbose:
print(str(self.t) + "\t" + shout)
def record(self):
with open(self.filename, "a") as f:
line = ""
# Format will be edgeIdent,nodeAident,nodeBident
line += str("t=" + str(self.t) + ",")
ordKeyList = sorted(list(self.state.edges.keys()))
for key in ordKeyList:
entry = []
entry.append(key)
nodeKeyList = sorted(list(self.state.edges[key].nodes))
for kkey in nodeKeyList:
entry.append(kkey)
line += str(entry) + ","
f.write(line + "\n")
class Test_FishGraph(unittest.TestCase):
def test_fishGraph(self):
for i in range(10):
params = {"numNodes":10, "probEdge":0.5, "maxNeighbors":10, "maxTime":10.0, "birthRate":0.1, "deathRate":0.1}
greg = FishGraph(params, verbosity=True)
greg.go()
suite = unittest.TestLoader().loadTestsFromTestCase(Test_FishGraph)
unittest.TextTestRunner(verbosity=1).run(suite)

View file

@ -1,101 +1,187 @@
from Edge import * from Blockchain import *
from Node import *
from Edge import *
from copy import *
def newIntensity(params):
x = random.random()
return x
def newOffset(params):
x = 2.0*random.random() - 1.0
return x
class Graph(object): class Graph(object):
''' '''
Graph object. Contains some data, a dict of nodes, and a dict of edges. Explanation
''' '''
def __init__(self, params={}, verbosity=True): def __init__(self, params):
self.data=params
self.verbose = verbosity
self.nodes = {} self.nodes = {}
self.edges = {} self.edges = {}
self.mode = params[0]
self.targetRate = params[1]
self.numInitNodes = params[2]
self.maxNeighbors = params[3]
self.probEdge = params[4]
self.verbosity = params[5]
self.startTime = deepcopy(time.time())
self.runTime = params[6]
self.globalTime = deepcopy(self.startTime)
self.birthRate = params[7]
self.deathRate = params[8]
self.data = params[9]
def createGraph(self, numNodes, probEdge, maxNeighbors): self.blankBlockchain = Blockchain()
# Create a new random graph with numNodes nodes, a self.blankBlockchain.targetRate = self.data["targetRate"]
# likelihood any unordered pair of vertices has an edge self.blankBlockchain.mode = self.data["mode"]
# probEdge, and maximum number of neighbors per node
# maxNeighbors.
# First, include inputted information into self.data self._createInit()
self.data.update({"probEdge":probEdge, "maxNeighbors":maxNeighbors})
def _createInit(self):
# For simplicity, all nodes will have a genesis block with t=0.0 and no offset
for i in range(self.numInitNodes):
offset = newOffset()
intens = newIntensity()
name = newIdent(len(self.nodes))
dat = {"offset":offset, "intensity":intens, "blockchain":deepcopy(self.blankBlockchain)}
params = {"ident":name, "data":dat, "verbose":self.verbosity, "mode":self.mode, "targetRate":self.targetRate}
nelly = Node(params)
self.nodes.update({nelly.ident:nelly})
t = self.startTime
self.nodes[nelly.ident].generateBlock(t, i)
touched = {}
for xNode in self.nodes:
for yNode in self.nodes:
notSameNode = (xNode != yNode)
xNodeHasRoom = (len(self.nodes[xNode].edges) < self.maxNeighbors)
yNodeHasRoom = (len(self.ndoes[yNode].edges) < self.maxNeighbors)
xyNotTouched = ((xNode, yNode) not in touched)
yxNotTouched = ((yNode, xNode) not in touched)
if notSameNode and xNodeHasRoom and yNodeHasRoom and xyNotTouched and yxNotTouched:
touched.update({(xNode,yNode):True, (yNode,xNode):True})
if random.random() < self.probEdge:
params = [newIdent(len(self.edges)), {}, self.verbosity]
ed = Edge(params)
ed.nodes.update({xNode:self.nodes[xNode], yNode:self.nodes[yNode]})
self.edges.update({ed.ident:ed})
self.nodes[xNode].edges.update({ed.ident:ed})
self.nodes[yNode].edges.update({ed.ident:ed})
def eventNodeJoins(self, t):
# timestamp,nodeJoins,numberNeighbors,neighbor1.ident,edge1.ident,neighbor2.ident,edge2.ident,...,
out = ""
neighbors = []
for xNode in self.nodes:
xNodeHasRoom = (len(self.nodes[xNode].edges) < self.maxNeighbors)
iStillHasRoom = (len(neighbors) < self.maxNeighbors)
if xNodeHasRoom and and iStillHasRoom and random.random() < self.probEdge:
neighbors.append(xNode)
newNodeName = newIdent(len(self.nodes))
offset = newOffset()
intens = newIntensity()
dat = {"offset":offset, "intensity":intens, "blockchain":deepcopy(self.blankBlockchain)}
params = {"ident":newNodeName, "data":dat, "verbose":self.verbosity, "mode":self.mode, "targetRate":self.targetRate}
newNode = Node(params)
self.nodes.update({newNode.ident:newNode})
self.nodes[newNode.ident].generateBlock(self.startTime, 0)
out = str(t) + ",nodeJoins," + str(newNode.ident) + "," + str(len(neighbors)) + ","
for neighbor in neighbors:
out += neighbor + ","
params = [newIdent(len(self.edges)), {}, self.verbosity]
ed = Edge(params)
ed.nodes.update({neighbor:self.nodes[neighbor], newNode.ident:self.nodes[newNode.ident]})
out += ed.ident + ","
self.edges.update({ed.ident:ed})
self.nodes[neighbor].edges.update({ed.ident:ed})
self.nodes[newNode.ident].edges.update({ed.ident:ed})
return out
def eventNodeLeaves(self, t):
out = str(t) + ",nodeLeaves,"
leaverIdent = random.choice(list(self.nodes.keys()))
out += str(leaverIdent) + ","
leaver = self.nodes[leaverIdent]
neighbors = []
for ed in leaver.edges:
neighbors.append((ed.Ident, ed.getNeighbor(leaverIdent)))
for neighbor in neighbors:
edIdent = neighbor[0]
neiIdent = neighbor[1]
del self.nodes[neiIdent].edges[edIdent]
del self.edges[edIdent]
del self.nodes[leaverIdent]
return out
def eventBlockDiscovery(self, discoIdent, t):
out = str(t) + ",blockDisco," + str(discoIdent) + ","
blockIdent = self.nodes[discoIdent].generateBlock(t)
out += str(blockIdent)
self.nodes[discoIdent].propagate(t, blockIdent)
return out
def eventBlockArrival(self, destNodeIdent, edgeIdent, blockIdent, t):
out = str(t) + ",blockArriv," + str(destNodeIdent) + "," + str(edgeIdent) + "," + str(blockIdent) + ","
destNode = self.nodes[destNodeIdent]
edge = self.edges[edgeIdent]
block = deepcopy(edge.data["pendingBlocks"][blockIdent])
block.arrivTimestamp = t + self.nodes[destNodeIdent].data["offset"]
self.nodes[destNodeIdent].updateBlockchain({blockIdent:block})
return out
def go(self):
with open(self.filename,"w") as writeFile:
writeFile.write("timestamp,eventId,eventData\n")
while self.globalTime - self.startTime< self.runTime:
u = -1.0*math.log(1.0-random.random())/self.birthRate
eventType = ("nodeJoins", None)
v = -1.0*math.log(1.0-random.random())/self.deathRate
if v < u:
eventType = ("nodeLeaves", None)
u = v
for nodeIdent in self.nodes:
localBlockDiscoRate = self.nodes[nodeIdent].data["intensity"]/self.nodes[nodeIdent].data["blockchain"].diff
v = -1.0*math.log(1.0-random.random())/localBlockDiscoRate
if v < u:
eventType = ("blockDisco", nodeIdent)
u = v
for edgeIdent in self.edges:
edge = self.edges[edgeIdent]
pB = edge.data["pendingBlocks"]
for pendingIdent in pB:
pendingData = pB[pendingIdent] # pendingDat = {"timeOfArrival":timeOfArrival, "destIdent":otherIdent, "block":blockToProp}
if pendingData["timeOfArrival"] - self.globalTime < u:
eventTime = ("blockArriv", (pendingData["destIdent"], edgeIdent, pendingData["block"]))
u = v
self.globalTime += u
out = ""
if eventTime[0] == "nodeJoins":
out = self.eventNodeJoins(self.globalTime)
elif eventTime[0] == "nodeLeaves":
out = self.eventNodeLeaves(self.globalTime)
elif eventTime[0] == "blockDisco":
out = self.eventBlockDiscovery(eventTime[1], self.globalTime)
elif eventTime[0] == "blockArriv":
out = self.eventBlockArrival(eventTime[1], eventTime[2], eventTime[3], self.globalTime)
else:
print("WHAAAA")
with open(self.filename, "a") as writeFile:
writeFile.write(out + "\n")
# Next, for each node to be added, create the node and name it.
for i in range(numNodes):
nIdent = newIdent(i)
bl = Blockchain([], verbosity=True)
dat = {"blockchain":bl, "intensity":newIntensity(["uniform"]), "offset":newOffset("sumOfSkellams")}
# A node needs an ident, a data object, a verbosity, and a difficulty
n = Node([nIdent, dat, self.verbose, 1.0])
self.nodes.update({n.ident:n})
# Next, for each possible node pair, decide if an edge exists.
touched = {} # Dummy list of node pairs we have already considered.
for nIdent in self.nodes:
n = self.nodes[nIdent] # Pick a node
for mIdent in self.nodes:
m = self.nodes[mIdent] # Pick a pair element
notSameNode = (nIdent != mIdent) # Ensure we aren't dealing with (x,x)
nOpenSlots = (len(n.edges) < self.data["maxNeighbors"]) # ensure both nodes have open slots available for new edges
mOpenSlots = (len(m.edges) < self.data["maxNeighbors"])
untouched = ((nIdent, mIdent) not in touched) # make sure the pair and its transposition have not been touched
dehcuotnu = ((mIdent, nIdent) not in touched)
if notSameNode and nOpenSlots and mOpenSlots and untouched and dehcuotnu:
# Mark pair as touhed
touched.update({(nIdent,mIdent):True, (mIdent,nIdent):True})
if random.random() < self.data["probEdge"]:
# Determine if edge should exist and if so, add it.
nonce = len(self.edges)
e = Edge([newIdent(nonce),{"length":random.random(), "pendingBlocks":[]},self.verbose])
e.nodes.update({n.ident:n, m.ident:m})
self.nodes[nIdent].edges.update({e.ident:e})
self.nodes[mIdent].edges.update({e.ident:e})
self.edges.update({e.ident:e})
def addNode(self):
# Add new node
n = Node([newIdent(len(self.nodes)), {}, self.verbose, 1.0])
self.nodes.update({n.ident:n})
for mIdent in self.nodes:
# For every other node, check if an edge should exist and if so add it.
m = self.nodes[mIdent]
notSameNode = (n.ident != mIdent)
nOpenSlots = (len(n.edges) < self.data["maxNeighbors"])
mOpenSlots = (len(m.edges) < self.data["maxNeighbors"])
if notSameNode and nOpenSlots and mOpenSlots and random.random() < self.data["probEdge"]:
nonce = len(self.edges)
e = Edge([newIdent(nonce), {"length":random.random(), "pendingBlocks":[]}, self.verbose])
e.nodes.update({n.ident:n, m.ident:m})
n.edges.update({e.ident:e})
self.nodes[mIdent].edges.update({e.ident:e})
self.edges.update({e.ident:e})
return n.ident
def delNode(self, ident):
# Remove a node and wipe all memory of its edges from history.
edgesToDelete = self.nodes[ident].edges
for edgeIdent in edgesToDelete:
e = edgesToDelete[edgeIdent]
otherIdent = e.getNeighbor(ident)
del self.edges[edgeIdent]
del self.nodes[otherIdent].edges[edgeIdent]
del self.nodes[ident]
class Test_Graph(unittest.TestCase):
def test_graph(self):
greg = Graph()
greg.createGraph(3, 0.5, 10)
self.assertEqual(len(greg.nodes),3)
greg.addNode()
self.assertEqual(len(greg.nodes),4)
for edge in greg.edges:
self.assertEqual(len(greg.edges[edge].nodes),2)
nodeToKill = random.choice(list(greg.nodes.keys()))
greg.delNode(nodeToKill)
for edge in greg.edges:
self.assertEqual(len(greg.edges[edge].nodes),2)
for nodeIdent in greg.edges[edge].nodes:
self.assertTrue(nodeIdent in greg.nodes)
suite = unittest.TestLoader().loadTestsFromTestCase(Test_Graph)
unittest.TextTestRunner(verbosity=1).run(suite)

File diff suppressed because it is too large Load diff

View file

@ -1,53 +0,0 @@
import unittest, random, time
class StochasticProcess(object):
'''
Stochastic processes have a clock and a state.
The clock moves forward, and then the state updates.
More detail requires knowledge of the underlying stochProc.
'''
def __init__(self, params=None):
# initialize with initial data
self.data = params
self.t = 0.0 # should always start at t=0.0
self.state = 0.0 # magic number
self.maxTime = 1000.0 # magic number
self.saveFile = "output.csv"
self.verbose = True
def go(self):
# Executes stochastic process.
assert self.maxTime > 0.0 # Check loop will eventually terminate.
t = self.t
while t <= self.maxTime:
deltaT = self.getNextTime() # Pick the next "time until event" and a description of the event.
self.updateState(t, deltaT) # Update state with deltaT input
t = self.t
if self.verbose:
print("Recording...")
self.record()
def getNextTime(self):
return 1 # Magic number right now
def updateState(self, t, deltaT):
# Update the state of the system. In this case,
# we are doing a random walk on the integers.
self.state += random.randrange(-1,2,1) # [-1, 0, 1]
self.t += deltaT
def record(self):
with open(self.saveFile,"w") as recordKeeper:
line = str(self.t) + ",\t" + str(self.state) + "\n"
recordKeeper.write(line)
class Test_StochasticProcess(unittest.TestCase):
def test_sp(self):
sally = StochasticProcess()
sally.verbose = False
sally.go()
suite = unittest.TestLoader().loadTestsFromTestCase(Test_StochasticProcess)
unittest.TextTestRunner(verbosity=1).run(suite)

View file

@ -1,46 +0,0 @@
import unittest, random, time
def newIdent(params):
nonce = params
# Generate new random identity.
return hash(str(nonce) + str(random.random()))
#### #### #### #### #### #### #### #### #### #### #### #### #### #### #### ####
class Block(object):
'''
Each block has: an identity, a timestamp of discovery (possibly false),
has a timestamp of arrival at the local node (possibly unnecessary), a
parent block's identity, and a difficulty score.
'''
def __init__(self, params={}):
self.ident = None
self.discoTimestamp = None
self.arrivTimestamp = None
self.parent = None
self.diff = None
try:
assert len(params)==5
except AssertionError:
print("Error in Block(): Tried to add a malformed block. We received params = " + str(params) + ", but should have had something of the form {\"ident\":ident, \"disco\":disco, \"arriv\":arriv, \"parent\":parent, \"diff\":diff}.")
self.ident = params["ident"]
self.discoTimestamp = params["disco"]
self.arrivTimestamp = params["arriv"]
self.parent = params["parent"]
self.diff = params["diff"]
class Test_Block(unittest.TestCase):
def test_b(self):
#bill = Block()
name = newIdent(0)
t = time.time()
s = t+1
diff = 1.0
params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff}
bill = Block(params)
self.assertEqual(bill.ident,name)
self.assertEqual(bill.discoTimestamp,t)
self.assertEqual(bill.arrivTimestamp,t+1)
self.assertTrue(bill.parent is None)
self.assertEqual(bill.diff,diff)
suite = unittest.TestLoader().loadTestsFromTestCase(Test_Block)
unittest.TextTestRunner(verbosity=1).run(suite)

View file

@ -1,46 +0,0 @@
import unittest, random, time
def newIdent(params):
nonce = params
# Generate new random identity.
return hash(str(nonce) + str(random.random()))
#### #### #### #### #### #### #### #### #### #### #### #### #### #### #### ####
class Block(object):
'''
Each block has: an identity, a timestamp of discovery (possibly false),
has a timestamp of arrival at the local node (possibly unnecessary), a
parent block's identity, and a difficulty score.
'''
def __init__(self, params={}):
self.ident = None
self.discoTimestamp = None
self.arrivTimestamp = None
self.parent = None
self.diff = None
try:
assert len(params)==5
except AssertionError:
print("Error in Block(): Tried to add a malformed block. We received params = " + str(params) + ", but should have had something of the form {\"ident\":ident, \"disco\":disco, \"arriv\":arriv, \"parent\":parent, \"diff\":diff}.")
self.ident = params["ident"]
self.discoTimestamp = params["disco"]
self.arrivTimestamp = params["arriv"]
self.parent = params["parent"]
self.diff = params["diff"]
class Test_Block(unittest.TestCase):
def test_b(self):
#bill = Block()
name = newIdent(0)
t = time.time()
s = t+1
diff = 1.0
params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff}
bill = Block(params)
self.assertEqual(bill.ident,name)
self.assertEqual(bill.discoTimestamp,t)
self.assertEqual(bill.arrivTimestamp,t+1)
self.assertTrue(bill.parent is None)
self.assertEqual(bill.diff,diff)
suite = unittest.TestLoader().loadTestsFromTestCase(Test_Block)
unittest.TextTestRunner(verbosity=1).run(suite)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,116 +0,0 @@
from Blockchain import *
class Node(object):
'''
Node object. params [identity, blockchain (data), verbosity, difficulty]
'''
def __init__(self, params={}):
try:
assert len(params)==5
except AssertionError:
print("Error, Tried to create malformed node.")
else:
self.ident = params["ident"]
self.data = params["data"]
self.verbose = params["verbose"]
self.edges = {}
self.mode = params["mode"]
self.targetRate = params["targetRate"]
def generateBlock(self, discoTime, nonce):
newName = newIdent(nonce)
t = discoTime
s = t+self.data["offset"]
diff = self.data["blockchain"].diff
params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff}
newBlock = Block(params)
self.data["blockchain"].addBlock(newBlock, mode, tr)
return newName
def updateBlockchain(self, incBlocks):
# incBlocks shall be a dictionary of block identities (as keys) and their associated blocks (as values)
# to be added to the local data. We assume difficulty scores have been reported honestly for now.
tempData = copy.deepcopy(incBlocks)
for key in incBlocks:
if key in self.data["blockchain"].blocks:
del tempData[key]
elif incBlocks[key].parent in self.data["blockchain"].blocks or incBlocks[key].parent is None:
self.data["blockchain"].addBlock(incBlocks[key], self.mode, self.targetRate)
del tempData[key]
incBlocks = copy.deepcopy(tempData)
while len(incBlocks)>0:
for key in incBlocks:
if key in self.data["blockchain"].blocks:
del tempData[key]
elif incBlocks[key].parent in self.data["blockchain"].blocks:
self.data["blockchain"].addBlock(incBlocks[key], self.mode, self.targetRate)
del tempData[key]
incBlocks = copy.deepcopy(tempData)
def propagate(self, timeOfProp, blockIdent):
for edgeIdent in self.edges:
edge = self.edges[edgeIdent]
length = e.data["length"]
timeOfArrival = timeOfProp + length
otherIdent = e.getNeighbor(self.ident)
other = e.nodes[otherIdent]
bc = other.data["blockchain"]
if blockIdent not in bc.blocks:
pB = e.data["pendingBlocks"]
pendingIdent = newIdent(len(pB))
mybc = self.data["blockchain"]
blockToProp = mybc.blocks[blockIdent]
pendingDat = {"timeOfArrival":timeOfArrival, "destIdent":otherIdent, "block":blockToProp}
pB.update({pendingIdent:pendingDat})
class Test_Node(unittest.TestCase):
# TODO test each method separately
def test_all(self):
bill = Blockchain([], verbosity=True)
mode="Nakamoto"
tr = 1.0/600000.0
deltaT = 600000.0
bill.targetRate = tr
name = newIdent(0)
t = 0.0
s = t
diff = 1.0
params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff}
genesis = Block(params)
bill.addBlock(genesis, mode, tr)
parent = genesis.ident
nellyname = newIdent(time.time())
mode = "Nakamoto"
targetRate = 1.0/600000.0
params = {"ident":nellyname, "data":{"offset":0.0, "intensity":1.0, "blockchain":bill}, "verbose":True, "mode":mode, "targetRate":targetRate}
nelly = Node(params)
while len(nelly.data["blockchain"].blocks) < 2015:
name = newIdent(0)
diff = nelly.data["blockchain"].diff
t += deltaT*diff*(2.0*random.random()-1.0)
s = t
params = {"ident":name, "disco":t, "arriv":s, "parent":parent, "diff":diff}
newBlock = Block(params)
bill.addBlock(newBlock, mode, tr)
parent = name
while len(nelly.data["blockchain"].blocks) < 5000:
name = newIdent(0)
diff = nelly.data["blockchain"].diff
t += deltaT*diff
s = t
params = {"ident":name, "disco":t, "arriv":s, "parent":parent, "diff":diff}
newBlock = Block(params)
bill.addBlock(newBlock, mode, tr)
parent = name
suite = unittest.TestLoader().loadTestsFromTestCase(Test_Node)
unittest.TextTestRunner(verbosity=1).run(suite)

View file

@ -1,116 +0,0 @@
from Blockchain import *
class Node(object):
'''
Node object. params [identity, blockchain (data), verbosity, difficulty]
'''
def __init__(self, params={}):
try:
assert len(params)==5
except AssertionError:
print("Error, Tried to create malformed node.")
else:
self.ident = params["ident"]
self.data = params["data"]
self.verbose = params["verbose"]
self.edges = {}
self.mode = params["mode"]
self.targetRate = params["targetRate"]
def generateBlock(self, discoTime, nonce):
newName = newIdent(nonce)
t = discoTime
s = t+self.data["offset"]
diff = self.data["blockchain"].diff
params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff}
newBlock = Block(params)
self.data["blockchain"].addBlock(newBlock, mode, tr)
return newName
def updateBlockchain(self, incBlocks):
# incBlocks shall be a dictionary of block identities (as keys) and their associated blocks (as values)
# to be added to the local data. We assume difficulty scores have been reported honestly for now.
tempData = copy.deepcopy(incBlocks)
for key in incBlocks:
if key in self.data["blockchain"].blocks:
del tempData[key]
elif incBlocks[key].parent in self.data["blockchain"].blocks or incBlocks[key].parent is None:
self.data["blockchain"].addBlock(incBlocks[key], self.mode, self.targetRate)
del tempData[key]
incBlocks = copy.deepcopy(tempData)
while len(incBlocks)>0:
for key in incBlocks:
if key in self.data["blockchain"].blocks:
del tempData[key]
elif incBlocks[key].parent in self.data["blockchain"].blocks:
self.data["blockchain"].addBlock(incBlocks[key], self.mode, self.targetRate)
del tempData[key]
incBlocks = copy.deepcopy(tempData)
def propagate(self, timeOfProp, blockIdent):
for edgeIdent in self.edges:
edge = self.edges[edgeIdent]
length = e.data["length"]
timeOfArrival = timeOfProp + length
otherIdent = e.getNeighbor(self.ident)
other = e.nodes[otherIdent]
bc = other.data["blockchain"]
if blockIdent not in bc.blocks:
pB = e.data["pendingBlocks"]
pendingIdent = newIdent(len(pB))
mybc = self.data["blockchain"]
blockToProp = mybc.blocks[blockIdent]
pendingDat = {"timeOfArrival":timeOfArrival, "destIdent":otherIdent, "block":blockToProp}
pB.update({pendingIdent:pendingDat})
class Test_Node(unittest.TestCase):
# TODO test each method separately
def test_all(self):
bill = Blockchain([], verbosity=True)
mode="Nakamoto"
tr = 1.0/600000.0
deltaT = 600000.0
bill.targetRate = tr
name = newIdent(0)
t = 0.0
s = t
diff = 1.0
params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff}
genesis = Block(params)
bill.addBlock(genesis, mode, tr)
parent = genesis.ident
nellyname = newIdent(time.time())
mode = "Nakamoto"
targetRate = 1.0/600000.0
params = {"ident":nellyname, "data":{"offset":0.0, "intensity":1.0, "blockchain":bill}, "verbose":True, "mode":mode, "targetRate":targetRate}
nelly = Node(params)
while len(nelly.data["blockchain"].blocks) < 2015:
name = newIdent(0)
diff = nelly.data["blockchain"].diff
t += deltaT*diff*(2.0*random.random()-1.0)
s = t
params = {"ident":name, "disco":t, "arriv":s, "parent":parent, "diff":diff}
newBlock = Block(params)
bill.addBlock(newBlock, mode, tr)
parent = name
while len(nelly.data["blockchain"].blocks) < 5000:
name = newIdent(0)
diff = nelly.data["blockchain"].diff
t += deltaT*diff
s = t
params = {"ident":name, "disco":t, "arriv":s, "parent":parent, "diff":diff}
newBlock = Block(params)
bill.addBlock(newBlock, mode, tr)
parent = name
suite = unittest.TestLoader().loadTestsFromTestCase(Test_Node)
unittest.TextTestRunner(verbosity=1).run(suite)

File diff suppressed because it is too large Load diff

View file

@ -1,602 +0,0 @@
time,rateConstant,difficulty
0.0,1.0,1.0
1.0,1.0,1.0
2.0,1.0,1.0
3.0,1.0,1.0
4.0,1.0,1.0
5.0,1.0,1.0
6.0,1.0,1.0
7.0,1.0,1.0
8.0,1.0,1.0
9.0,1.0,1.0
10.0,1.0,1.0
11.0,1.0,1.0
12.0,1.0,1.0
13.0,1.0,1.0
14.0,1.0,1.0
15.0,1.0,1.0
16.0,1.0,1.0
17.0,1.0,1.0
18.0,1.0,1.0
19.0,1.0,1.0
20.0,1.0,1.0
21.0,1.0,1.0
22.0,1.0,1.0
23.0,1.0,1.0
24.0,1.0,1.0
25.0,1.0,1.0
26.0,1.0,1.0
27.0,1.0,1.0
28.0,1.0,1.0
29.0,1.0,1.0
30.0,1.0,1.0
31.0,1.0,1.0
32.0,1.0,1.0
33.0,1.0,1.0
34.0,1.0,1.0
35.0,1.0,1.0
36.0,1.0,1.0
37.0,1.0,1.0
38.0,1.0,1.0
39.0,1.0,1.0
40.0,1.0,1.0
41.0,1.0,1.0
42.0,1.0,1.0
43.0,1.0,1.0
44.0,1.0,1.0
45.0,1.0,1.0
46.0,1.0,1.0
47.0,1.0,1.0
48.0,1.0,1.0
49.0,1.0,1.0
50.0,1.0,1.0
51.0,1.0,1.0
52.0,1.0,1.0
53.0,1.0,1.0
54.0,1.0,1.0
55.0,1.0,1.0
56.0,1.0,1.0
57.0,1.0,1.0
58.0,1.0,1.0
59.0,1.0,1.0
60.0,1.0,1.0
61.0,1.0,1.0
62.0,1.0,1.0
63.0,1.0,1.0
64.0,1.0,1.0
65.0,1.0,1.0
66.0,1.0,1.0
67.0,1.0,1.0
68.0,1.0,1.0
69.0,1.0,1.0
70.0,1.0,1.0
71.0,1.0,1.0
72.0,1.0,1.0
73.0,1.0,1.0
74.0,1.0,1.0
75.0,1.0,1.0
76.0,1.0,1.0
77.0,1.0,1.0
78.0,1.0,1.0
79.0,1.0,1.0
80.0,1.0,1.0
81.0,1.0,1.0
82.0,1.0,1.0
83.0,1.0,1.0
84.0,1.0,1.0
85.0,1.0,1.0
86.0,1.0,1.0
87.0,1.0,1.0
88.0,1.0,1.0
89.0,1.0,1.0
90.0,1.0,1.0
91.0,1.0,1.0
92.0,1.0,1.0
93.0,1.0,1.0
94.0,1.0,1.0
95.0,1.0,1.0
96.0,1.0,1.0
97.0,1.0,1.0
98.0,1.0,1.0
99.0,1.0,1.0
100.0,1.0,1.0
101.0,1.0,1.0
102.0,1.0,1.0
103.0,1.0,1.0
104.0,1.0,1.0
105.0,1.0,1.0
106.0,1.0,1.0
107.0,1.0,1.0
108.0,1.0,1.0
109.0,1.0,1.0
110.0,1.0,1.0
111.0,1.0,1.0
112.0,1.0,1.0
113.0,1.0,1.0
114.0,1.0,1.0
115.0,1.0,1.0
116.0,1.0,1.0
117.0,1.0,1.0
118.0,1.0,1.0
119.0,1.0,1.0
120.0,1.0,1.0
121.0,1.0,1.0
122.0,1.0,1.0
123.0,1.0,1.0
124.0,1.0,1.0
125.0,1.0,1.0
126.0,1.0,1.0
127.0,1.0,1.0
128.0,1.0,1.0
129.0,1.0,1.0
130.0,1.0,1.0
131.0,1.0,1.0
132.0,1.0,1.0
133.0,1.0,1.0
134.0,1.0,1.0
135.0,1.0,1.0
136.0,1.0,1.0
137.0,1.0,1.0
138.0,1.0,1.0
139.0,1.0,1.0
140.0,1.0,1.0
141.0,1.0,1.0
142.0,1.0,1.0
143.0,1.0,1.0
144.0,1.0,1.0
145.0,1.0,1.0
146.0,1.0,1.0
147.0,1.0,1.0
148.0,1.0,1.0
149.0,1.0,1.0
150.0,1.0,1.0
151.0,1.0,1.0
152.0,1.0,1.0
153.0,1.0,1.0
154.0,1.0,1.0
155.0,1.0,1.0
156.0,1.0,1.0
157.0,1.0,1.0
158.0,1.0,1.0
159.0,1.0,1.0
160.0,1.0,1.0
161.0,1.0,1.0
162.0,1.0,1.0
163.0,1.0,1.0
164.0,1.0,1.0
165.0,1.0,1.0
166.0,1.0,1.0
167.0,1.0,1.0
168.0,1.0,1.0
169.0,1.0,1.0
170.0,1.0,1.0
171.0,1.0,1.0
172.0,1.0,1.0
173.0,1.0,1.0
174.0,1.0,1.0
175.0,1.0,1.0
176.0,1.0,1.0
177.0,1.0,1.0
178.0,1.0,1.0
179.0,1.0,1.0
180.0,1.0,1.0
181.0,1.0,1.0
182.0,1.0,1.0
183.0,1.0,1.0
184.0,1.0,1.0
185.0,1.0,1.0
186.0,1.0,1.0
187.0,1.0,1.0
188.0,1.0,1.0
189.0,1.0,1.0
190.0,1.0,1.0
191.0,1.0,1.0
192.0,1.0,1.0
193.0,1.0,1.0
194.0,1.0,1.0
195.0,1.0,1.0
196.0,1.0,1.0
197.0,1.0,1.0
198.0,1.0,1.0
199.0,1.0,1.0
200.0,1.0,1.0
201.0,1.0,1.0
202.0,1.0,1.0
203.0,1.0,1.0
204.0,1.0,1.0
205.0,1.0,1.0
206.0,1.0,1.0
207.0,1.0,1.0
208.0,1.0,1.0
209.0,1.0,1.0
210.0,1.0,1.0
211.0,1.0,1.0
212.0,1.0,1.0
213.0,1.0,1.0
214.0,1.0,1.0
215.0,1.0,1.0
216.0,1.0,1.0
217.0,1.0,1.0
218.0,1.0,1.0
219.0,1.0,1.0
220.0,1.0,1.0
221.0,1.0,1.0
222.0,1.0,1.0
223.0,1.0,1.0
224.0,1.0,1.0
225.0,1.0,1.0
226.0,1.0,1.0
227.0,1.0,1.0
228.0,1.0,1.0
229.0,1.0,1.0
230.0,1.0,1.0
231.0,1.0,1.0
232.0,1.0,1.0
233.0,1.0,1.0
234.0,1.0,1.0
235.0,1.0,1.0
236.0,1.0,1.0
237.0,1.0,1.0
238.0,1.0,1.0
239.0,1.0,1.0
240.0,1.0,1.0
241.0,1.0,1.0
242.0,1.0,1.0
243.0,1.0,1.0
244.0,1.0,1.0
245.0,1.0,1.0
246.0,1.0,1.0
247.0,1.0,1.0
248.0,1.0,1.0
249.0,1.0,1.0
250.0,1.0,1.0
251.0,1.0,1.0
252.0,1.0,1.0
253.0,1.0,1.0
254.0,1.0,1.0
255.0,1.0,1.0
256.0,1.0,1.0
257.0,1.0,1.0
258.0,1.0,1.0
259.0,1.0,1.0
260.0,1.0,1.0
261.0,1.0,1.0
262.0,1.0,1.0
263.0,1.0,1.0
264.0,1.0,1.0
265.0,1.0,1.0
266.0,1.0,1.0
267.0,1.0,1.0
268.0,1.0,1.0
269.0,1.0,1.0
270.0,1.0,1.0
271.0,1.0,1.0
272.0,1.0,1.0
273.0,1.0,1.0
274.0,1.0,1.0
275.0,1.0,1.0
276.0,1.0,1.0
277.0,1.0,1.0
278.0,1.0,1.0
279.0,1.0,1.0
280.0,1.0,1.0
281.0,1.0,1.0
282.0,1.0,1.0
283.0,1.0,1.0
284.0,1.0,1.0
285.0,1.0,1.0
286.0,1.0,1.0
287.0,1.0,1.0
288.0,1.0,1.0
289.0,1.0,1.0
290.0,1.0,1.0
291.0,1.0,1.0
292.0,1.0,1.0
293.0,1.0,1.0
294.0,1.0,1.0
295.0,1.0,1.0
296.0,1.0,1.0
297.0,1.0,1.0
298.0,1.0,1.0
299.0,1.0,1.0
300.0,1.0,1.0
301.0,1.0,1.0
302.0,1.0,1.0
303.0,1.0,1.0
304.0,1.0,1.0
305.0,1.0,1.0
306.0,1.0,1.0
307.0,1.0,1.0
308.0,1.0,1.0
309.0,1.0,1.0
310.0,1.0,1.0
311.0,1.0,1.0
312.0,1.0,1.0
313.0,1.0,1.0
314.0,1.0,1.0
315.0,1.0,1.0
316.0,1.0,1.0
317.0,1.0,1.0
318.0,1.0,1.0
319.0,1.0,1.0
320.0,1.0,1.0
321.0,1.0,1.0
322.0,1.0,1.0
323.0,1.0,1.0
324.0,1.0,1.0
325.0,1.0,1.0
326.0,1.0,1.0
327.0,1.0,1.0
328.0,1.0,1.0
329.0,1.0,1.0
330.0,1.0,1.0
331.0,1.0,1.0
332.0,1.0,1.0
333.0,1.0,1.0
334.0,1.0,1.0
335.0,1.0,1.0
336.0,1.0,1.0
337.0,1.0,1.0
338.0,1.0,1.0
339.0,1.0,1.0
340.0,1.0,1.0
341.0,1.0,1.0
342.0,1.0,1.0
343.0,1.0,1.0
344.0,1.0,1.0
345.0,1.0,1.0
346.0,1.0,1.0
347.0,1.0,1.0
348.0,1.0,1.0
349.0,1.0,1.0
350.0,1.0,1.0
351.0,1.0,1.0
352.0,1.0,1.0
353.0,1.0,1.0
354.0,1.0,1.0
355.0,1.0,1.0
356.0,1.0,1.0
357.0,1.0,1.0
358.0,1.0,1.0
359.0,1.0,1.0
360.0,1.0,1.0
361.0,1.0,1.0
362.0,1.0,1.0
363.0,1.0,1.0
364.0,1.0,1.0
365.0,1.0,1.0
366.0,1.0,1.0
367.0,1.0,1.0
368.0,1.0,1.0
369.0,1.0,1.0
370.0,1.0,1.0
371.0,1.0,1.0
372.0,1.0,1.0
373.0,1.0,1.0
374.0,1.0,1.0
375.0,1.0,1.0
376.0,1.0,1.0
377.0,1.0,1.0
378.0,1.0,1.0
379.0,1.0,1.0
380.0,1.0,1.0
381.0,1.0,1.0
382.0,1.0,1.0
383.0,1.0,1.0
384.0,1.0,1.0
385.0,1.0,1.0
386.0,1.0,1.0
387.0,1.0,1.0
388.0,1.0,1.0
389.0,1.0,1.0
390.0,1.0,1.0
391.0,1.0,1.0
392.0,1.0,1.0
393.0,1.0,1.0
394.0,1.0,1.0
395.0,1.0,1.0
396.0,1.0,1.0
397.0,1.0,1.0
398.0,1.0,1.0
399.0,1.0,1.0
400.0,1.0,1.0
401.0,1.0,1.0
402.0,1.0,1.0
403.0,1.0,1.0
404.0,1.0,1.0
405.0,1.0,1.0
406.0,1.0,1.0
407.0,1.0,1.0
408.0,1.0,1.0
409.0,1.0,1.0
410.0,1.0,1.0
411.0,1.0,1.0
412.0,1.0,1.0
413.0,1.0,1.0
414.0,1.0,1.0
415.0,1.0,1.0
416.0,1.0,1.0
417.0,1.0,1.0
418.0,1.0,1.0
419.0,1.0,1.0
420.0,1.0,1.0
421.0,1.0,1.0
422.0,1.0,1.0
423.0,1.0,1.0
424.0,1.0,1.0
425.0,1.0,1.0
426.0,1.0,1.0
427.0,1.0,1.0
428.0,1.0,1.0
429.0,1.0,1.0
430.0,1.0,1.0
431.0,1.0,1.0
432.0,1.0,1.0
433.0,1.0,1.0
434.0,1.0,1.0
435.0,1.0,1.0
436.0,1.0,1.0
437.0,1.0,1.0
438.0,1.0,1.0
439.0,1.0,1.0
440.0,1.0,1.0
441.0,1.0,1.0
442.0,1.0,1.0
443.0,1.0,1.0
444.0,1.0,1.0
445.0,1.0,1.0
446.0,1.0,1.0
447.0,1.0,1.0
448.0,1.0,1.0
449.0,1.0,1.0
450.0,1.0,1.0
451.0,1.0,1.0
452.0,1.0,1.0
453.0,1.0,1.0
454.0,1.0,1.0
455.0,1.0,1.0
456.0,1.0,1.0
457.0,1.0,1.0
458.0,1.0,1.0
459.0,1.0,1.0
460.0,1.0,1.0
461.0,1.0,1.0
462.0,1.0,1.0
463.0,1.0,1.0
464.0,1.0,1.0
465.0,1.0,1.0
466.0,1.0,1.0
467.0,1.0,1.0
468.0,1.0,1.0
469.0,1.0,1.0
470.0,1.0,1.0
471.0,1.0,1.0
472.0,1.0,1.0
473.0,1.0,1.0
474.0,1.0,1.0
475.0,1.0,1.0
476.0,1.0,1.0
477.0,1.0,1.0
478.0,1.0,1.0
479.0,1.0,1.0
480.0,1.0,1.0
481.0,1.0,1.0
482.0,1.0,1.0
483.0,1.0,1.0
484.0,1.0,1.0
485.0,1.0,1.0
486.0,1.0,1.0
487.0,1.0,1.0
488.0,1.0,1.0
489.0,1.0,1.0
490.0,1.0,1.0
491.0,1.0,1.0
492.0,1.0,1.0
493.0,1.0,1.0
494.0,1.0,1.0
495.0,1.0,1.0
496.0,1.0,1.0
497.0,1.0,1.0
498.0,1.0,1.0
499.0,1.0,1.0
500.0,1.0,1.0
501.0,1.0,1.0
502.0,1.0,1.0
503.0,1.0,1.0
504.0,1.0,1.0
505.0,1.0,1.0
506.0,1.0,1.0
507.0,1.0,1.0
508.0,1.0,1.0
509.0,1.0,1.0
510.0,1.0,1.0
511.0,1.0,1.0
512.0,1.0,1.0
513.0,1.0,1.0
514.0,1.0,1.0
515.0,1.0,1.0
516.0,1.0,1.0
517.0,1.0,1.0
518.0,1.0,1.0
519.0,1.0,1.0
520.0,1.0,1.0
521.0,1.0,1.0
522.0,1.0,1.0
523.0,1.0,1.0
524.0,1.0,1.0
525.0,1.0,1.0
526.0,1.0,1.0
527.0,1.0,1.0
528.0,1.0,1.0
529.0,1.0,1.0
530.0,1.0,1.0
531.0,1.0,1.0
532.0,1.0,1.0
533.0,1.0,1.0
534.0,1.0,1.0
535.0,1.0,1.0
536.0,1.0,1.0
537.0,1.0,1.0
538.0,1.0,1.0
539.0,1.0,1.0
540.0,1.0,1.0
541.0,1.0,1.0
542.0,1.0,1.0
543.0,1.0,1.0
544.0,1.0,1.0
545.0,1.0,1.0
546.0,1.0,1.0
547.0,1.0,1.0
548.0,1.0,1.0
549.0,1.0,1.0
550.0,1.0,1.0
551.0,1.0,1.0
552.0,1.0,1.0
553.0,1.0,1.0
554.0,1.0,1.0
555.0,1.0,1.0
556.0,1.0,1.0
557.0,1.0,1.0
558.0,1.0,1.0
559.0,1.0,1.0
560.0,1.0,1.0
561.0,1.0,1.0
562.0,1.0,1.0
563.0,1.0,1.0
564.0,1.0,1.0
565.0,1.0,1.0
566.0,1.0,1.0
567.0,1.0,1.0
568.0,1.0,1.0
569.0,1.0,1.0
570.0,1.0,1.0
571.0,1.0,1.0
572.0,1.0,1.0
573.0,1.0,1.0
574.0,1.0,1.0
575.0,1.0,1.0
576.0,1.0,1.0
577.0,1.0,1.0
578.0,1.0,1.0
579.0,1.0,1.0
580.0,1.0,1.0
581.0,1.0,1.0
582.0,1.0,1.0
583.0,1.0,1.0
584.0,1.0,1.0
585.0,1.0,1.0
586.0,1.0,1.0
587.0,1.0,1.0
588.0,1.0,1.0
589.0,1.0,1.0
590.0,1.0,1.0
591.0,1.0,1.0
592.0,1.0,1.0
593.0,1.0,1.0
594.0,1.0,1.0
595.0,1.0,1.0
596.0,1.0,1.0
597.0,1.0,1.0
598.0,1.0,1.0
599.0,1.0,1.0
600.0,1.0,1.0

View file

@ -1,201 +0,0 @@
time,rateConstant,difficulty
0.0,1.0,1.0
120458.46590012926,1.0,1.0
240605.33373578714,1.0,1.0
360287.44233708055,1.0,1.0
480034.84471731156,1.0,1.0
601021.4072874074,1.0,1.0
720155.9397105722,1.0,1.0
840557.1097845419,1.0,1.0
960142.4715273783,1.0,1.0
1080326.4196690398,1.0,1.0
1200228.3567496322,1.0,1.0
1321393.1769845556,1.0,1.0
1442403.7637959223,1.0,1.0
1563312.6884154421,1.0,1.0
1683650.3562759135,1.0,1.0
1804242.0878089573,1.0,1.0
1923957.6270508477,1.0,1.0
2043603.5193920576,1.0,1.0
2162815.4440224506,1.0,1.0
2282288.929005547,1.0,1.0
2402114.705755926,1.0,1.0
2522303.585101224,1.0,1.0
2643267.2988593285,1.0,1.0
2762617.5338163865,1.0,1.0
2882563.380726947,1.0,1.0
3003489.532699132,1.0,1.0
3124641.562256374,1.0,1.0
3245100.9215427977,1.0,1.0
3365536.420458877,1.0,1.0
3484337.996609595,1.0,1.0
3604694.7847104715,1.0,1.0
3724951.576782264,1.0,1.0
3846026.69613723,1.0,1.0
3967024.7982774274,1.0,1.0
4085911.063711746,1.0,1.0
4205815.028144305,1.0,1.0
4325421.232620401,1.0,1.0
4444827.052513202,1.0,1.0
4565099.154304211,1.0,1.0
4686236.387124661,1.0,1.0
4806734.051850467,1.0,1.0
4926566.647937627,1.0,1.0
5045488.866484466,1.0,1.0
5166502.755345808,1.0,1.0
5287233.653263695,1.0,1.0
5407908.334559678,1.0,1.0
5528786.366282915,1.0,1.0
5647678.3122160155,1.0,1.0
5767244.089580304,1.0,1.0
5886473.651601109,1.0,1.0
6006435.897878854,1.0,1.0
6125341.27352921,1.0,1.0
6245479.785253891,1.0,1.0
6365523.236878065,1.0,1.0
6485749.795878896,1.0,1.0
6605240.444894265,1.0,1.0
6724686.210446132,1.0,1.0
6844155.218750592,1.0,1.0
6963341.181369955,1.0,1.0
7082695.6923123505,1.0,1.0
7203655.141225615,1.0,1.0
7322627.204840391,1.0,1.0
7441799.159546731,1.0,1.0
7562822.49932097,1.0,1.0
7683323.524066307,1.0,1.0
7804477.48899398,1.0,1.0
7923457.857637024,1.0,1.0
8043898.249303401,1.0,1.0
8164187.296374614,1.0,1.0
8283469.107294493,1.0,1.0
8402627.723784521,1.0,1.0
8523745.89200794,1.0,1.0
8643778.9729813,1.0,1.0
8764635.624631569,1.0,1.0
8885538.059417976,1.0,1.0
9006433.79263568,1.0,1.0
9127489.588015186,1.0,1.0
9247569.28782317,1.0,1.0
9367958.084440755,1.0,1.0
9487586.29442678,1.0,1.0
9606427.886281481,1.0,1.0
9725872.946140163,1.0,1.0
9846820.596317865,1.0,1.0
9966080.313457007,1.0,1.0
10085765.108573573,1.0,1.0
10206008.374459436,1.0,1.0
10326807.845790997,1.0,1.0
10447513.423168132,1.0,1.0
10566795.347145824,1.0,1.0
10686179.997466285,1.0,1.0
10805522.808373246,1.0,1.0
10925591.945700001,1.0,1.0
11045387.795286857,1.0,1.0
11165651.717103494,1.0,1.0
11286830.098064246,1.0,1.0
11406728.71699933,1.0,1.0
11525922.789870113,1.0,1.0
11646476.03903497,1.0,1.0
11766081.434268286,1.0,1.0
11886554.737807736,1.0,1.0
12006591.066234503,1.0,1.0
12125475.542528223,1.0,1.0
12245282.608027933,1.0,1.0
12364566.337023206,1.0,1.0
12484001.537563423,1.0,1.0
12604914.58673975,1.0,1.0
12725797.319719713,1.0,1.0
12844665.121160349,1.0,1.0
12964577.111847764,1.0,1.0
13083664.372389417,1.0,1.0
13204397.122438395,1.0,1.0
13324189.80038166,1.0,1.0
13445349.787586372,1.0,1.0
13564667.751049513,1.0,1.0
13684270.141374838,1.0,1.0
13804933.175467426,1.0,1.0
13926075.032552686,1.0,1.0
14045914.739095576,1.0,1.0
14166631.90042476,1.0,1.0
14286319.61550191,1.0,1.0
14406521.722056692,1.0,0.434741782576
14527069.972553544,1.0,0.19008730551
14647876.788742132,1.0,0.0840528337448
14766882.452974409,1.0,0.037302520528
14886464.10335911,1.0,0.0165590754676
15006383.983595744,1.0,0.00734675515331
15125494.942906044,1.0,0.00323569454228
15246686.831929097,1.0,0.00142738653296
15365567.953963466,1.0,0.000625305203658
15485210.071059253,1.0,0.00027137099116
15605744.64157258,1.0,0.00011715461834
15726806.733151415,1.0,5.07010986398e-05
15847473.63409661,1.0,2.20995440742e-05
15967616.71119521,1.0,9.7101015984e-06
16087483.017800437,1.0,4.29503052419e-06
16208328.180223988,1.0,1.92536966438e-06
16328269.772618307,1.0,8.74191715802e-07
16448898.77254663,1.0,4.04296324402e-07
16569068.683560552,1.0,1.90818902578e-07
16689986.260285133,1.0,9.28633545485e-08
16810906.032656457,1.0,4.72143204458e-08
16930289.120968327,1.0,2.49711320542e-08
17050753.779718515,1.0,1.3892256413e-08
17170600.427019596,1.0,8.15844774794e-09
17289713.01359109,1.0,4.99225078962e-09
17410383.421790008,1.0,3.25190780354e-09
17530744.28431112,1.0,2.30869255122e-09
17649863.36025036,1.0,1.75633116174e-09
17771007.11205409,1.0,1.56057621444e-09
17891565.791564044,1.0,2.04725172611e-09
18010728.55130284,1.0,3.28303372549e-09
18131143.8843602,1.0,3.25496154055e-09
18251685.45446652,1.0,2.60736708269e-09
18371507.007102486,1.0,1.85630105501e-09
18491403.948076807,1.0,1.21928659457e-09
18611553.039604228,1.0,7.49792394597e-10
18730744.251551468,1.0,4.45186327526e-10
18849856.685056694,1.0,2.61385070862e-10
18968926.062500622,1.0,1.55149613051e-10
19088067.33909847,1.0,9.51850841053e-11
19207594.13354391,1.0,6.1434055957e-11
19328017.11208744,1.0,4.14815251504e-11
19448814.951942917,1.0,2.86357848006e-11
19567841.28162038,1.0,2.11150220091e-11
19688388.179414563,1.0,1.6406642243e-11
19807627.873820234,1.0,1.43187359575e-11
19928483.04169874,1.0,1.35913238196e-11
20048557.76424465,1.0,1.4331290576e-11
20167664.74191137,1.0,2.37342192382e-11
20287610.467802733,1.0,3.14063325262e-11
20408382.62417472,1.0,3.36556321046e-11
20527817.08243184,1.0,3.00938650991e-11
20646637.59478427,1.0,2.24650389033e-11
20766577.880066067,1.0,1.49080962166e-11
20885785.934438772,1.0,8.89077367161e-12
21005536.07104386,1.0,4.87060433801e-12
21124902.305172637,1.0,2.47052077112e-12
21244885.7076036,1.0,1.17786853388e-12
21364581.43746038,1.0,5.31532928098e-13
21484493.676516064,1.0,2.28757375026e-13
21603916.644479226,1.0,9.40324531004e-14
21723733.860411238,1.0,3.70938898759e-14
21844771.38186735,1.0,1.42162474893e-14
21964794.368862327,1.0,5.30817642226e-15
22085627.151319932,1.0,1.94525471916e-15
22205153.52382764,1.0,6.9852514309e-16
22324878.40351138,1.0,2.45757880538e-16
22444702.60558849,1.0,8.47565473955e-17
22564133.40356277,1.0,2.8611824903e-17
22684916.550748322,1.0,9.50429614301e-18
22804924.811821572,1.0,3.10972949853e-18
22924555.89776567,1.0,1.00142181128e-18
23044673.155832924,1.0,3.17850639386e-19
23164255.219417505,1.0,9.93453168398e-20
23283874.042637054,1.0,3.05585142432e-20
23403159.90787814,1.0,9.23510334381e-21
23522146.490881946,1.0,2.7354446299e-21
23641985.23572208,1.0,7.94854774163e-22
23760806.412928328,1.0,2.26044417743e-22
23881715.30956635,1.0,6.31881915952e-23