Skip to content

Commit

Permalink
Merge pull request #243 from MM1nd/prepare_faster_random_land
Browse files Browse the repository at this point in the history
Prepare faster random land
  • Loading branch information
ftomassetti committed Sep 30, 2017
2 parents 3a65092 + 66895a4 commit 88f0235
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 7 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Version 0.20 (UNRELEASED)

* Caclulation of sea depth is now faster.
* Calculation of sea depth is now faster.

Version 0.19

Expand Down
77 changes: 77 additions & 0 deletions tests/simulation_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import unittest

import numpy

from worldengine.simulations.hydrology import WatermapSimulation
from worldengine.model.world import World, Size, GenerationParameters

class TestSimulation(unittest.TestCase):


# The hydrology simulation indirectly calls the global rng.
# We want different implementations of _watermap
# and internally called functions (especially random_land)
# to show the same rng behaviour and not contamine the state of the global rng
# should anyone else happen to rely on it.
# This does only test that watermap leaves the rng in the state that the
# original implementation would have left it in and that a very small sample
# of results is the same as the original results.
# It does not test if the implementation is actually correct.
# In fact it is hard to tell how "correctness" of a Monte Carlo process should
# be judged.
# Should it ever be decided that a "correct" implementation needs fewer or
# more calls to the rng, relative to the n parameter,
# of course compatibility will be broken.
# Implicitly this is tested by the blessed images but it might be useful to
# have a finer grained picture.

def test_watermap_rng_stabilty(self):

seed=12345
numpy.random.seed(seed)

size = Size(16,8)

ocean = numpy.fromfunction(lambda y, x: y==x, (size.height, size.width))

percipitation = numpy.ones((size.height, size.width))

elevation = numpy.fromfunction(lambda y, x: y*x, (size.height, size.width))

t = numpy.zeros(5)

w = World("watermap", size, seed, GenerationParameters(0, 1.0, 0))
w.ocean = ocean
w.precipitation = (percipitation, t)
w.elevation = (elevation, t)

d = numpy.random.randint(0,100)
self.assertEqual(d, 98)

data, t = WatermapSimulation._watermap(w, 200)

self.assertAlmostEqual(data[4,4], 0.0)
self.assertAlmostEqual(data[3,5], 4.20750776)

d = numpy.random.randint(0,100)
self.assertEqual(d, 59)

def test_random_land_returns_only_land(self):

size = Size(100,90)

ocean = numpy.fromfunction(lambda y, x: y>=x, (size.height, size.width))

w = World("random_land", size, 0, GenerationParameters(0, 1.0, 0))
w.ocean = ocean

num_samples = 1000

land_indices = w.random_land(num_samples)

for i in range(0, num_samples*2, 2):
self.assertFalse(ocean[land_indices[i+1],land_indices[i]])


if __name__ == '__main__':
unittest.main()
2 changes: 1 addition & 1 deletion worldengine/common.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys
import numpy #for the _equal method only
import numpy

# ----------------
# Global variables
Expand Down
18 changes: 13 additions & 5 deletions worldengine/model/world.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,13 +396,21 @@ def contains(self, pos):
# Land/Ocean
#

def random_land(self):
def random_land(self, num_samples=1):

if self.layers['ocean'].data.all():
return None, None # return invalid indices if there is no land at all
lands = numpy.invert(self.layers['ocean'].data)
lands = numpy.transpose(lands.nonzero()) # returns a list of tuples/indices with land positions
y, x = lands[numpy.random.randint(0, len(lands))] # uses global RNG
return x, y

land = numpy.invert(self.layers['ocean'].data)
land_indices = numpy.transpose(numpy.nonzero(land)) # returns a list of tuples/indices with land positions

result = numpy.zeros(num_samples*2, dtype=int)

for i in range(0, num_samples*2, 2):
r_num = numpy.random.randint(0, len(land_indices)) # uses global RNG
result[i+1], result[i] = land_indices[r_num]

return result

def is_land(self, pos):
return not self.layers['ocean'].data[pos[1], pos[0]]#faster than reversing pos or transposing ocean
Expand Down

0 comments on commit 88f0235

Please sign in to comment.