import numpy as np
import scipy.ndimage
import matplotlib.pyplot as plt
import time
Naive Generator
A generator that implemented based on
scipy.ndimage
Generating a latent space representation
To make it more “understandable” where material is placed we generate a slowly varying landscape by interpolation of a low resolution map.
= 8
features = 16
zoom = np.random.random((features,features))-0.5
heatmap = scipy.ndimage.zoom(heatmap, zoom)
large_heatmap
plt.imshow(large_heatmap)"x")
plt.xlabel("y")
plt.ylabel( plt.grid()
Generating the brush
=9
kernel_size= np.ones((kernel_size, kernel_size))
brush 0,0] = 0
brush[0,-1] = 0
brush[-1,0] = 0
brush[-1,-1] = 0
brush[
= brush.shape
nx, ny
plt.imshow(brush)= plt.gca()
ax +0.5)
ax.set_yticks(np.arange(nx)"" for i in range(nx)])
ax.set_yticklabels([+0.5)
ax.set_xticks(np.arange(ny)"" for i in range(ny)])
ax.set_xticklabels([=True)
ax.set_yticks(np.arange(nx), minorf"{i}" for i in range(nx)], minor=True)
ax.set_yticklabels([=True)
ax.set_xticks(np.arange(ny), minorf"{i}" for i in range(ny)], minor=True)
ax.set_xticklabels([ plt.grid()
Running the Generator
def dilate(img, brush):
global time_dilate
-= time.process_time()
time_dilate = scipy.ndimage.morphology.binary_dilation(img, brush)
dil += time.process_time()
time_dilate return dil
def existing_pixels(touches, brush):
return dilate(touches, brush)
def impossible_touches(existing_other, brush):
return dilate(existing_other, brush)
def valid_touches(impossible, touches):
return np.logical_and(np.logical_not(impossible), np.logical_not(touches))
def possible_pixels(valid, touches, brush):
= np.logical_or(touches, valid)
possible_touches return dilate(possible_touches, brush)
def required_pixels(existing, possible_other):
return np.logical_and(np.logical_not(existing), np.logical_not(possible_other))
def resolving_touches(required, valid, brush):
return np.logical_and(dilate(required, brush), valid)
def free_touches(possible_other, existing_other, valid, brush):
= dilate(np.logical_or(possible_other, existing_other), brush)
dilated return np.logical_and(np.logical_not(dilated), valid)
def select_single(s_valid, v_valid, s_suggest, v_suggest, brush, t_s, t_v):
= scipy.ndimage.convolve(s_suggest, brush)
s_weights = -scipy.ndimage.convolve(v_suggest, brush)
v_weights
= np.nan
s_weights[np.logical_not(s_valid)] = np.nan
v_weights[np.logical_not(v_valid)]
= max_v = -np.inf
max_s if s_valid.any():
= np.nanargmax(s_weights)
max_pos_s = s_weights.flat[max_pos_s]
max_s
if v_valid.any():
= np.nanargmax(v_weights)
max_pos_v = v_weights.flat[max_pos_v]
max_v
if max_s > max_v:
= True
t_s.flat[max_pos_s] else:
= True
t_v.flat[max_pos_v]
return t_s, t_v
= large_heatmap.copy()
s_suggest = large_heatmap.copy()
v_suggest = np.zeros_like(s_suggest).astype(bool)
t_s = t_s.copy()
t_v
= 0
time_update = 0
time_select = 0
time_dilate = 0
time_existing = 0
time_impossible = 0
time_valid = 0
time_possible = 0
time_required = 0
time_resolving = 0
time_free
= True
debug def log(*args):
if debug:
print(*args)
for i in range(10000):
-= time.process_time()
time_update
-= time.process_time()
time_existing = existing_pixels(t_s, brush)
p_s_existing = existing_pixels(t_v, brush)
p_v_existing += time.process_time()
time_existing
= 0
s_suggest[p_s_existing] = 0
v_suggest[p_v_existing]
-= time.process_time()
time_impossible = impossible_touches(p_v_existing, brush)
t_s_impossible = impossible_touches(p_s_existing, brush)
t_v_impossible += time.process_time()
time_impossible
-= time.process_time()
time_valid = valid_touches(t_s_impossible, t_s)
t_s_valid = valid_touches(t_v_impossible, t_v)
t_v_valid += time.process_time()
time_valid
-= time.process_time()
time_possible = possible_pixels(t_s_valid,t_s,brush)
p_s_possible = possible_pixels(t_v_valid,t_v,brush)
p_v_possible += time.process_time()
time_possible
-= time.process_time()
time_required = required_pixels(p_s_existing, p_v_possible)
p_s_required = required_pixels(p_v_existing, p_s_possible)
p_v_required += time.process_time()
time_required
-= time.process_time()
time_resolving = resolving_touches(p_s_required, t_s_valid, brush)
t_s_resolving = resolving_touches(p_v_required, t_v_valid, brush)
t_v_resolving += time.process_time()
time_resolving
-= time.process_time()
time_free = free_touches(p_v_possible, p_v_existing, t_s_valid, brush)
t_s_free = free_touches(p_s_possible, p_s_existing, t_v_valid, brush)
t_v_free += time.process_time()
time_free
+= time.process_time()
time_update -= time.process_time()
time_select
if t_s_free.any() or t_v_free.any():
f"{i}: free")
log(= np.logical_or(t_s, t_s_free)
t_s = np.logical_or(t_v, t_v_free)
t_v elif t_s_resolving.any() or t_v_resolving.any():
f"{i}: resolving")
log(= select_single(t_s_resolving, t_v_resolving, s_suggest, v_suggest, brush, t_s, t_v)
t_s, t_v elif t_s_valid.any() or t_v_valid.any():
f"{i}: valid")
log(= select_single(t_s_valid, t_v_valid, s_suggest, v_suggest, brush, t_s, t_v)
t_s, t_v else:
print("finished")
+= time.process_time()
time_select break
+= time.process_time()
time_select
= (6,9))
plt.figure(figsize 321)
plt.subplot("Solid")
plt.title(
plt.imshow(p_s_existing)322)
plt.subplot("Void")
plt.title(
plt.imshow(p_v_existing)323)
plt.subplot("Solid Touches")
plt.title(
plt.imshow(t_s)324)
plt.subplot("Void Touches")
plt.title(
plt.imshow(t_v)325)
plt.subplot( plt.imshow(large_heatmap)
/tmp/ipykernel_3808/3885273807.py:4: DeprecationWarning: Please use `binary_dilation` from the `scipy.ndimage` namespace, the `scipy.ndimage.morphology` namespace is deprecated.
dil = scipy.ndimage.morphology.binary_dilation(img, brush)
0: valid
1: valid
2: valid
3: free
4: valid
5: valid
6: resolving
7: free
8: valid
9: valid
10: resolving
11: free
12: valid
13: resolving
14: free
15: valid
16: valid
17: free
18: valid
19: resolving
20: free
21: valid
22: resolving
23: free
24: valid
25: free
26: valid
27: valid
28: resolving
29: free
30: valid
31: resolving
32: free
33: valid
34: resolving
35: free
36: valid
37: valid
38: resolving
39: free
40: valid
41: free
42: resolving
43: free
44: valid
45: resolving
46: free
47: valid
48: resolving
49: free
50: valid
51: free
52: valid
53: resolving
54: free
55: valid
56: valid
57: free
58: resolving
59: free
60: resolving
61: free
62: resolving
63: free
64: resolving
65: free
66: valid
67: free
68: valid
69: valid
70: free
71: valid
72: free
73: valid
74: valid
75: free
76: valid
77: free
78: valid
79: free
80: valid
81: free
82: valid
83: free
84: resolving
85: free
86: valid
87: free
88: resolving
89: free
90: valid
91: valid
92: resolving
93: free
94: valid
95: valid
96: resolving
97: free
98: valid
99: valid
100: valid
101: free
102: valid
103: valid
104: resolving
105: free
106: valid
107: resolving
108: free
109: resolving
110: free
111: valid
112: free
113: valid
114: free
115: resolving
116: free
117: valid
118: free
119: valid
120: free
121: valid
122: free
123: valid
124: valid
125: resolving
126: free
127: valid
128: free
129: valid
130: valid
131: free
132: valid
133: free
134: resolving
135: valid
136: free
137: valid
138: valid
139: free
140: resolving
141: free
142: valid
143: free
144: resolving
145: free
146: valid
147: resolving
148: free
149: resolving
150: free
151: valid
152: resolving
153: free
154: resolving
155: free
156: resolving
157: free
158: valid
159: free
160: resolving
161: free
162: resolving
163: free
164: valid
165: free
166: resolving
167: free
168: valid
169: valid
170: resolving
171: free
172: valid
173: free
174: valid
175: free
176: valid
177: valid
178: free
179: valid
180: valid
181: free
182: valid
183: valid
184: free
185: valid
186: resolving
187: free
188: valid
189: free
190: valid
191: free
192: resolving
193: free
194: resolving
195: free
196: valid
197: free
198: valid
199: free
200: valid
201: free
202: valid
203: free
204: resolving
205: free
206: resolving
207: free
208: resolving
209: free
210: valid
211: resolving
212: free
213: resolving
214: free
215: valid
216: free
217: valid
218: free
219: valid
220: free
221: resolving
222: resolving
223: free
224: valid
225: valid
226: free
227: valid
228: free
229: valid
230: free
231: valid
232: free
233: valid
234: free
235: resolving
236: free
237: valid
238: free
239: valid
240: free
241: valid
242: free
243: valid
244: free
245: valid
246: free
247: valid
248: free
249: valid
250: free
251: resolving
252: free
253: resolving
254: free
255: resolving
256: free
257: resolving
258: free
259: valid
260: free
261: valid
262: free
263: valid
264: free
265: valid
266: free
267: valid
268: free
269: valid
270: resolving
271: free
272: resolving
273: free
274: resolving
275: resolving
276: free
277: resolving
278: free
279: valid
280: free
281: valid
282: free
283: valid
284: free
285: valid
286: free
287: valid
288: free
289: valid
290: free
291: valid
292: free
293: valid
294: free
295: resolving
296: free
297: resolving
298: free
299: valid
300: free
301: valid
302: free
303: valid
304: free
305: valid
306: free
307: valid
308: free
309: resolving
310: free
311: resolving
312: free
313: valid
314: free
315: valid
316: free
317: valid
318: free
319: valid
320: free
321: valid
322: free
323: valid
324: free
325: valid
326: free
327: valid
328: free
329: valid
330: free
331: valid
332: free
333: valid
334: free
335: valid
336: free
337: valid
338: free
339: valid
340: free
341: valid
342: free
343: valid
344: free
345: valid
346: free
347: valid
348: free
349: valid
350: free
351: valid
352: free
353: valid
354: free
355: valid
356: free
357: valid
358: free
359: valid
360: free
361: valid
362: free
363: valid
364: free
365: valid
366: free
367: valid
368: free
369: valid
370: free
371: valid
372: free
373: valid
374: free
375: valid
376: free
377: valid
378: free
379: valid
380: free
381: valid
382: free
383: valid
384: free
385: valid
386: free
387: valid
388: free
389: valid
390: free
391: valid
392: free
393: valid
394: free
395: valid
396: free
397: valid
398: free
399: valid
400: free
401: valid
402: free
403: valid
404: free
405: valid
406: free
407: valid
408: free
409: valid
410: free
411: valid
412: free
413: valid
414: free
415: valid
416: free
417: valid
418: free
419: valid
420: free
421: valid
422: free
423: valid
424: free
425: valid
426: free
427: valid
428: free
429: valid
430: free
431: valid
432: free
433: valid
434: free
435: valid
436: free
437: valid
438: free
439: valid
440: free
441: valid
442: free
443: valid
444: free
445: valid
446: free
447: valid
448: free
449: valid
450: free
451: valid
452: free
453: valid
454: free
455: valid
456: free
457: valid
458: free
459: valid
460: free
461: valid
462: free
463: valid
464: free
465: valid
466: valid
467: free
468: valid
469: free
470: valid
471: free
472: valid
473: free
474: valid
475: free
476: valid
477: free
478: valid
479: free
480: valid
481: valid
482: free
483: valid
484: free
485: valid
486: valid
487: free
488: valid
489: free
490: valid
491: free
492: valid
493: free
494: valid
495: free
496: valid
497: free
498: valid
499: free
500: valid
501: free
502: valid
503: free
504: valid
505: free
506: valid
507: free
508: valid
509: free
510: valid
511: valid
512: free
513: valid
514: free
515: valid
516: free
517: valid
518: free
519: valid
520: free
521: valid
522: free
523: valid
524: free
525: valid
526: free
527: valid
528: free
529: valid
530: free
531: valid
532: free
533: valid
534: valid
535: free
536: valid
537: free
538: valid
539: free
540: valid
541: valid
542: free
543: valid
544: free
545: valid
546: free
547: valid
548: free
549: valid
550: free
551: valid
552: free
553: valid
554: free
555: valid
556: free
557: valid
558: free
559: valid
560: free
561: valid
562: free
563: valid
564: free
565: valid
566: free
567: valid
568: free
569: valid
570: free
571: valid
572: free
573: valid
574: free
575: valid
576: free
577: valid
578: free
579: valid
580: free
581: valid
582: free
583: valid
584: valid
585: free
586: valid
587: valid
588: free
589: valid
590: valid
591: free
592: valid
593: free
594: valid
595: valid
596: free
597: valid
598: valid
599: valid
600: free
601: valid
602: valid
603: free
604: valid
605: free
606: valid
607: free
608: valid
609: free
610: valid
611: valid
612: valid
613: free
614: valid
615: valid
616: valid
617: valid
618: valid
finished
<matplotlib.image.AxesImage at 0x7f7f283cd100>
print(f"""
{time_update = }
{time_select = }
{time_dilate = }
{time_existing = }
{time_impossible = }
{time_valid = }
{time_possible = }
{time_required = }
{time_resolving = }
{time_free = }""")
time_update = 9.158790900000017
time_select = 1.343904300000009
time_dilate = 9.031094400000002
time_existing = 2.179708000000021
time_impossible = 1.7292600000000053
time_valid = 0.016886099999984694
time_possible = 1.3348817000000164
time_required = 0.014584900000011558
time_resolving = 2.914022299999994
time_free = 0.9344202000000212