def test_get_point_large_scan(self): s = SpiralGenerator(["x", "y"], "mm", [0, 0], 6, 1) #114 points z = LineGenerator("z", "mm", 0, 1, 100) w = LineGenerator("w", "mm", 0, 1, 5) t = LineGenerator("t", "mm", 0, 1, 5) rad1 = 2.8 r1 = CircularROI([1., 1.], rad1) e1 = ROIExcluder([r1], ["x", "y"]) rad2 = 2 r2 = CircularROI([0.5, 0.5], rad2) e2 = ROIExcluder([r2], ["y", "z"]) rad3 = 0.5 r3 = CircularROI([0.5, 0.5], rad3) e3 = ROIExcluder([r3], ["w", "t"]) g = CompoundGenerator([t, w, z, s], [e1, e2, e3], []) g.prepare() spiral = [(x, y) for (x, y) in zip(s.positions["x"], s.positions["y"])] zwt = [(z/99., w/4., t/4.) for t in range_(0, 5) for w in range_(0, 5) for z in range_(0, 100)] expected = [(x, y, z, w, t) for (z, w, t) in zwt for (x, y) in spiral] expected = [{"x":x, "y":y, "z":z, "w":w, "t":t} for (x,y,z,w,t) in expected if (x-1)*(x-1) + (y-1)*(y-1) <= rad1*rad1 and (y-0.5)*(y-0.5) + (z-0.5)*(z-0.5) <= rad2*rad2 and (w-0.5)*(w-0.5) + (t-0.5)*(t-0.5) <= rad3*rad3] points = [g.get_point(n) for n in range_(0, g.size)] pos = [p.positions for p in points] # assertEqual on a sequence of dicts is *really* slow for (e, p) in zip(expected, pos): self.assertEquals(e.keys(), p.keys()) for k in e.keys(): self.assertAlmostEqual(e[k], p[k])
def test_horrible_scan(self): lissajous = LissajousGenerator(["j1", "j2"], "mm", [-0.5, 0.7], [2, 3.5], 7, 100) line2 = LineGenerator(["l2"], "mm", -3, 3, 7, True) line1 = LineGenerator(["l1"], "mm", -1, 2, 5, True) spiral = SpiralGenerator(["s1", "s2"], "mm", [1, 2], 5, 2.5, True) r1 = CircularROI([1, 1], 2) r2 = CircularROI([-1, -1], 4) r3 = CircularROI([1, 1], 2) e1 = ROIExcluder([r1], ["j1", "l2"]) e2 = ROIExcluder([r2], ["s2", "l1"]) e3 = ROIExcluder([r3], ["s1", "s2"]) g = CompoundGenerator([lissajous, line2, line1, spiral], [e1, e2, e3], []) g.prepare() l2_f = True l1_f = True s_f = True points = [] for (j1, j2) in zip(lissajous.positions["j1"], lissajous.positions["j2"]): l2p = line2.positions["l2"] if l2_f else line2.positions["l2"][::-1] l2_f = not l2_f for l2 in l2p: l1p = line1.positions["l1"] if l1_f else line1.positions[ "l1"][::-1] l1_f = not l1_f for l1 in l1p: sp = zip(spiral.positions["s1"], spiral.positions["s2"]) if s_f \ else zip(spiral.positions["s1"][::-1], spiral.positions["s2"][::-1]) s_f = not s_f for (s1, s2) in sp: points.append((s1, s2, l1, l2, j1, j2)) self.assertEqual( lissajous.size * line2.size * line1.size * spiral.size, len(points)) points = [(s1, s2, l1, l2, j1, j2) for (s1, s2, l1, l2, j1, j2) in points if (j1 - 1)**2 + (l2 - 1)**2 <= 4 and (s2 + 1)**2 + (l1 + 1)**2 <= 16 and (s1 - 1)**2 + (s2 - 1)**2 <= 4] self.assertEqual(len(points), g.size) generated_points = list(g.iterator()) self.assertEqual(len(points), len(generated_points)) actual = [p.positions for p in generated_points] expected = [{ "j1": j1, "j2": j2, "l2": l2, "l1": l1, "s1": s1, "s2": s2 } for (s1, s2, l1, l2, j1, j2) in points] for e, a in zip(expected, actual): self.assertEqual(e, a) self.assertEqual((181, 10), g.shape)
def test_separate_indexes(self): x1 = LineGenerator("x1", "mm", -1.0, 1.0, 5, False) y1 = LineGenerator("y1", "mm", -1.0, 1.0, 5, False) z1 = LineGenerator("z1", "mm", -1.0, 1.0, 5, False) x2 = LineGenerator("x2", "mm", -1.0, 1.0, 5, False) y2 = LineGenerator("y2", "mm", -1.0, 1.0, 5, False) x3 = LineGenerator("x3", "mm", 0, 1.0, 5, False) y3 = LineGenerator("y3", "mm", 0, 1.0, 5, False) r = CircularROI([0, 0], 1) e1 = ROIExcluder([r], ["x1", "y1"]) e2 = ROIExcluder([r], ["y1", "z1"]) e3 = ROIExcluder([r], ["x1", "y1"]) e4 = ROIExcluder([r], ["x2", "y2"]) e5 = ROIExcluder([r], ["x3", "y3"]) g = CompoundGenerator([x3, y3, y2, x2, z1, y1, x1], [e1, e2, e3, e4, e5], []) g.prepare() p = [(x / 2., y / 2., z / 2.) for z in range_(-2, 3) for y in range_(-2, 3) for x in range_(-2, 3)] m1 = [x * x + y * y <= 1 for (x, y, z) in p] m2 = [y * y + z * z <= 1 for (x, y, z) in p] expected_mask = [(b1 and b2) for (b1, b2) in zip(m1, m2)] self.assertEqual(expected_mask, g.dimensions[2].mask.tolist()) p = [(x / 2., y / 2.) for y in range_(-2, 3) for x in range_(-2, 3)] expected_mask = [x * x + y * y <= 1 for (x, y) in p] self.assertEqual(expected_mask, g.dimensions[1].mask.tolist()) p = [(x / 4., y / 4.) for y in range_(0, 5) for x in range_(0, 5)] expected_mask = [x * x + y * y <= 1 for (x, y) in p] self.assertEqual(expected_mask, g.dimensions[0].mask.tolist())
def test_inner_alternating(self): z = LineGenerator("z", "mm", 1, 5, 5) y = LineGenerator("y", "mm", 1, 5, 5, alternate=True) x = LineGenerator("x", "mm", 1, 5, 5, alternate=True) r1 = CircularROI([3, 3], 1.5) e1 = ROIExcluder([r1], ["x", "y"]) g = CompoundGenerator([z, y, x], [e1], []) g.prepare() expected = [] xy_expected = [] x_f = True for y in range_(1, 6): for x in (range_(1, 6) if x_f else range(5, 0, -1)): if (x - 3)**2 + (y - 3)**2 <= 1.5**2: xy_expected.append((x, y)) x_f = not x_f xy_f = True for z in range_(1, 6): for (x, y) in (xy_expected if xy_f else xy_expected[::-1]): expected.append({"x": float(x), "y": float(y), "z": float(z)}) xy_f = not xy_f expected_idx = [] xy_f = True for z in range_(0, 5): xy_idx = range_(len(xy_expected)) if xy_f \ else range_(len(xy_expected)-1, -1, -1) expected_idx += [[z, xy] for xy in xy_idx] xy_f = not xy_f points = list(g.iterator()) self.assertEqual(expected, [p.positions for p in points]) self.assertEqual(expected_idx, [p.indexes for p in points])
def test_from_dict(self): g1 = LineGenerator("x1", "mm", -1.0, 1.0, 5, False) g1_dict = g1.to_dict() g2 = LineGenerator("y1", "mm", -1.0, 1.0, 5, False) g2_dict = g2.to_dict() r = CircularROI([0, 0], 1) excl_1 = ROIExcluder([r], ["x1", "y1"]) excl1_1_dict = excl_1.to_dict() mutator_1 = RandomOffsetMutator(0, ["x"], {"x": 1}) mutator_1_dict = mutator_1.to_dict() _dict = dict() _dict['generators'] = [g1_dict, g2_dict] _dict['excluders'] = [excl1_1_dict] _dict['mutators'] = [mutator_1_dict] _dict['duration'] = 12 _dict['continuous'] = False units_dict = dict() units_dict['x'] = 'mm' units_dict['y'] = 'mm' gen = CompoundGenerator.from_dict(_dict) self.assertEqual(gen.generators[0].to_dict(), g1.to_dict()) self.assertEqual(gen.generators[1].to_dict(), g2.to_dict()) self.assertEqual(gen.mutators[0].to_dict(), mutator_1.to_dict()) self.assertEqual(gen.excluders[0].to_dict(), excl_1.to_dict()) self.assertEqual(gen.duration, 12) self.assertEqual(gen.continuous, False)
def test_alternating_regions_2(self): z = LineGenerator("z", "mm", 1, 5, 5) y = LineGenerator("y", "mm", 1, 5, 5, True) x = LineGenerator("x", "mm", 1, 5, 5, True) r1 = CircularROI([3, 3], 1.5) e1 = ROIExcluder([r1], ["x", "y"]) e2 = ROIExcluder([r1], ["z", "y"]) g = CompoundGenerator([z, y, x], [e1, e2], []) #20 points g.prepare() actual = [p.positions for p in list(g.iterator())] expected = [] yf = True xf = True for z in range_(1, 6): yr = range_(1, 6) if yf else range_(5, 0, -1) yf = not yf for y in yr: xr = range_(1, 6) if xf else range_(5, 0, -1) xf = not xf for x in xr: expected.append({ "x": float(x), "y": float(y), "z": float(z) }) expected = [ p for p in expected if (p["x"] - 3)**2 + (p["y"] - 3)**2 <= 1.5**2 and (p["z"] - 3)**2 + (p["y"] - 3)**2 <= 1.5**2 ] self.assertEqual(expected, actual)
def test_staticpointgen_in_alternating(self): x = LineGenerator("x", "mm", 0, 1, 3, True) y = LineGenerator("y", "cm", 2, 3, 4, False) m = StaticPointGenerator(5) r = CircularROI((0.5, 2.5), 0.4) e = ROIExcluder([r], ["x", "y"]) g = CompoundGenerator([y, m, x], [e], []) g.prepare() expected_positions = [] x_positions = [0.0, 0.5, 1.0] direction = 1 for yp in [2.0, 2 + 1. / 3, 2 + 2. / 3, 3.0]: for mp in range_(5): for xp in x_positions[::direction]: if (xp - 0.5)**2 + (yp - 2.5)**2 <= 0.4**2: expected_positions.append({"y": yp, "x": xp}) direction *= -1 positions = [point.positions for point in g.iterator()] self.assertEqual(expected_positions, positions) self.assertEqual(len(expected_positions), g.size) self.assertEqual((len(expected_positions), ), g.shape) self.assertEqual(["y", "x"], g.axes) self.assertEqual({"y": "cm", "x": "mm"}, g.units) self.assertEqual(1, len(g.dimensions))
def test_excluder_spread_axes(self): sp = SpiralGenerator(["s1", "s2"], ["mm", "mm"], centre=[0, 0], radius=1, scale=0.5, alternate=True) y = LineGenerator("y", "mm", 0, 1, 3, True) z = LineGenerator("z", "mm", -2, 3, 6, True) e = ROIExcluder([CircularROI([0., 0.], 1.0)], ["s1", "z"]) g = CompoundGenerator([z, y, sp], [e], []) g.prepare() s1_pos, s2_pos = sp.positions["s1"], sp.positions["s2"] s1_pos = np.tile(np.append(s1_pos, s1_pos[::-1]), 9) s2_pos = np.tile(np.append(s2_pos, s2_pos[::-1]), 9) y_pos = np.tile(np.repeat(np.array([0, 0.5, 1.0, 1.0, 0.5, 0]), sp.size), 3) z_pos = np.repeat(np.array([-2, -1, 0, 1, 2, 3]), sp.size * 3) mask_func = lambda ps1, pz: ps1**2 + pz**2 <= 1 mask = mask_func(s1_pos, z_pos) expected_s1 = s1_pos[mask] expected_s2 = s2_pos[mask] expected_y = y_pos[mask] expected_z = z_pos[mask] expected_positions = [{'s1':ps1, 's2':ps2, 'y':py, 'z':pz} for (ps1, ps2, py, pz) in zip(expected_s1, expected_s2, expected_y, expected_z)] positions = [point.positions for point in list(g.iterator())] self.assertEqual(positions, expected_positions)
def test_three_dim_middle_alternates(self): tg = LineGenerator("t", "mm", 1, 5, 5) zg = LineGenerator("z", "mm", -1, 3, 5, True) spiral = SpiralGenerator(["s1", "s2"], "mm", [1, 1], 2, 1, True) yg = LineGenerator("y", "mm", 0, 4, 5) xg = LineGenerator("x", "mm", 0, 4, 5) r1 = CircularROI([0, 0], 1) e1 = ROIExcluder([r1], ["s1", "z"]) e2 = ROIExcluder([r1], ["y", "x"]) g = CompoundGenerator([tg, zg, spiral, yg, xg], [e2, e1], []) g.prepare() it = 0 iz = 0 iy = 0 ix = 0 tzs = [] points = [] for t in range_(1, 6): for z in (range_(-1, 4) if it % 2 == 0 else range_(3, -2, -1)): s1p = spiral.positions["s1"] if iz % 2 == 0 else spiral.positions["s1"][::-1] s2p = spiral.positions["s2"] if iz % 2 == 0 else spiral.positions["s2"][::-1] points += [(x, y, s1, s2, z, t) for (s1, s2) in zip(s1p, s2p) for y in range(0, 5) for x in range(0, 5) if s1*s1 + z*z <= 1 and y*y + x*x <= 1] iz += 1 it += 1 expected = [{"x":float(x), "y":float(y), "s1":s1, "s2":s2, "z":float(z), "t":float(t)} for (x, y, s1, s2, z, t) in points] actual = [p.positions for p in list(g.iterator())] for e, a in zip(expected, actual): self.assertEqual(e, a)
def test_complex_masks(self): tg = LineGenerator("t", "mm", 1, 5, 5) zg = LineGenerator("z", "mm", 0, 4, 5, alternate=True) yg = LineGenerator("y", "mm", 1, 5, 5, alternate=True) xg = LineGenerator("x", "mm", 2, 6, 5, alternate=True) r1 = CircularROI([4., 4.], 1.5) e1 = ROIExcluder([r1], ["y", "x"]) e2 = ROIExcluder([r1], ["z", "y"]) g = CompoundGenerator([tg, zg, yg, xg], [e1, e2], []) g.prepare() t_mask = [True] * 5 iy = 0 ix = 0 xyz_mask = [] xyz = [] for z in range_(0, 5): for y in (range_(1, 6) if iy % 2 == 0 else range_(5, 0, -1)): for x in (range_(2, 7) if ix % 2 == 0 else range_(6, 1, -1)): xyz_mask.append( (x-4)**2 + (y-4)**2 <= 1.5**2 \ and (y-4)**2 + (z-4)**2 <= 1.5**2) xyz.append((x, y, z)) ix += 1 iy += 1 self.assertEqual(t_mask, g.dimensions[0].mask.tolist()) self.assertEqual(xyz_mask, g.dimensions[1].mask.tolist())
def test_multi_roi_excluder(self): x = LineGenerator("x", "mm", 0.0, 4.0, 5, alternate=True) y = LineGenerator("y", "mm", 0.0, 3.0, 4) circles = ROIExcluder( [CircularROI([1.0, 2.0], 2.0), CircularROI([1.0, 2.0], 2.0)], ["x", "y"]) expected_positions = [{ 'x': 1.0, 'y': 0.0 }, { 'x': 2.0, 'y': 1.0 }, { 'x': 1.0, 'y': 1.0 }, { 'x': 0.0, 'y': 1.0 }, { 'x': 0.0, 'y': 2.0 }, { 'x': 1.0, 'y': 2.0 }, { 'x': 2.0, 'y': 2.0 }, { 'x': 3.0, 'y': 2.0 }, { 'x': 2.0, 'y': 3.0 }, { 'x': 1.0, 'y': 3.0 }, { 'x': 0.0, 'y': 3.0 }] g = CompoundGenerator([y, x], [circles], []) g.prepare() positions = [point.positions for point in list(g.iterator())] self.assertEqual(positions, expected_positions)
def test_double_spiral_scan(self): line1 = LineGenerator(["l1"], "mm", -1, 2, 5) spiral_s = SpiralGenerator(["s1", "s2"], "mm", [1, 2], 5, 2.5, True) spiral_t = SpiralGenerator(["t1", "t2"], "mm", [0, 0], 5, 2.5, True) line2 = LineGenerator(["l2"], "mm", -1, 2, 5, True) r = CircularROI([0, 0], 1) e1 = ROIExcluder([r], ["s1", "l1"]) e2 = ROIExcluder([r], ["l2", "t1"]) g = CompoundGenerator([line1, spiral_s, spiral_t, line2], [e1, e2], []) g.prepare() points = [] l1s = [] tl2 = [] s_f = True for l1 in line1.positions["l1"]: sp = zip(spiral_s.positions['s1'], spiral_s.positions['s2']) sp = sp if s_f else list(sp)[::-1] s_f = not s_f l1s += [(s1, s2, l1) for (s1, s2) in sp] l2_f = True for (t1, t2) in zip(spiral_t.positions['t1'], spiral_t.positions['t2']): l2p = line2.positions['l2'] if l2_f else line2.positions['l2'][::-1] l2pu = line2.bounds['l2'][1:len(line2.positions['l2'])+1] l2pl = line2.bounds['l2'][0:len(line2.positions['l2'])] if not l2_f: l2pu, l2pl = l2pl[::-1], l2pu[::-1] l2_f = not l2_f tl2 += [(l2, l2u, l2l, t1, t2) for (l2, l2u, l2l) in zip(l2p, l2pu, l2pl) if l2*l2 + t1*t1 <= 1] t_f = True for (s1, s2, l1) in l1s: inner = tl2 if t_f else tl2[::-1] t_f = not t_f points += [(l2, l2u, l2l, t1, t2, s1, s2, l1) for (l2, l2u, l2l, t1, t2) in inner if s1*s1 + l1*l1 <= 1] l1s_original = l1s l1s = [(s1, s2, l1) for (s1, s2, l1) in l1s if s1*s1 + l1*l1 <= 1] expected = [{"l2":l2, "t1":t1, "t2":t2, "s1":s1, "s2":s2, "l1":l1} for (l2, l2u, l2l, t1, t2, s1, s2, l1) in points] expected_idx = [] t_f = (l1s_original.index(l1s[0])) % 2 == 0 # t_f is False for d1 in range_(len(l1s)): expected_idx += [[d1, d2] for d2 in (range_(len(tl2)) if t_f else range_(len(tl2) - 1, -1, -1))] t_f = not t_f expected_l2_lower = [l2l for (l2, l2u, l2l, t1, t2, s1, s2, l1) in points] expected_l2_upper = [l2u for (l2, l2u, l2l, t1, t2, s1, s2, l1) in points] gpoints = list(g.iterator()) self.assertEqual(expected, [p.positions for p in gpoints]) self.assertEqual(expected_idx, [p.indexes for p in gpoints]) self.assertEqual(expected_l2_lower, [p.lower["l2"] for p in gpoints]) self.assertEqual(expected_l2_upper, [p.upper["l2"] for p in gpoints])
def test_simple_mask(self): x = LineGenerator("x", "mm", -1.0, 1.0, 5, False) y = LineGenerator("y", "mm", -1.0, 1.0, 5, False) r = CircularROI([0, 0], 1) e = ROIExcluder([r], ["x", "y"]) g = CompoundGenerator([y, x], [e], []) g.prepare() p = [(x / 2., y / 2.) for y in range_(-2, 3) for x in range_(-2, 3)] expected_mask = [x * x + y * y <= 1 for (x, y) in p] self.assertEqual(expected_mask, g.dimensions[0].mask.tolist())
def test_200_million_time_constraint(self): start_time = time.time() s = SpiralGenerator( ["x", "y"], "mm", [0, 0], 6, 0.02, True) # ~2e5 points z = LineGenerator("z", "mm", 0, 1, ZSIZE, True) #1e2 points or 1e1 for Jython w = LineGenerator("w", "mm", 0, 1, 10, True) #1e1 points r1 = CircularROI([-0.7, 4], 0.5) r2 = CircularROI([0.5, 0.5], 0.3) r3 = CircularROI([0.2, 4], 0.5) e1 = ROIExcluder([r1], ["x", "y"]) e2 = ROIExcluder([r2], ["w", "z"]) e3 = ROIExcluder([r3], ["z", "y"]) om = RandomOffsetMutator(0, ["x", "y"], {"x":0.2, "y":0.2}) g = CompoundGenerator([w, z, s], [e1, e3, e2], [om]) g.prepare() # g.size ~3e5 end_time = time.time() # if this test becomes problematic then we'll just have to remove it self.assertLess(end_time - start_time, TIMELIMIT)
def test_prepare_with_regions(self): x = LineGenerator("x", "mm", 0, 1, 5, False) y = LineGenerator("y", "mm", 0, 1, 5, False) circle = CircularROI([0., 0.], 1) excluder = ROIExcluder([circle], ['x', 'y']) g = CompoundGenerator([y, x], [excluder], []) g.prepare() self.assertEqual(1, len(g.dimensions)) self.assertEqual(["y", "x"], g.dimensions[0].axes) expected_mask = [(x / 4.)**2 + (y / 4.)**2 <= 1 for y in range(0, 5) for x in range(0, 5)] self.assertEqual(expected_mask, g.dimensions[0].mask.tolist()) self.assertEqual((len([v for v in expected_mask if v]), ), g.shape)
def test_double_mask(self): x = LineGenerator("x", "mm", -1.0, 1.0, 5, False) y = LineGenerator("y", "mm", -1.0, 1.0, 5, False) z = LineGenerator("z", "mm", -1.0, 1.0, 5, False) r = CircularROI([0.1, 0.2], 1) e1 = ROIExcluder([r], ["x", "y"]) e2 = ROIExcluder([r], ["y", "z"]) g = CompoundGenerator([z, y, x], [e1, e2], []) g.prepare() p = [(x / 2., y / 2., z / 2.) for z in range_(-2, 3) for y in range_(-2, 3) for x in range_(-2, 3)] m1 = [(x - 0.1)**2 + (y - 0.2)**2 <= 1 for (x, y, z) in p] m2 = [(y - 0.1)**2 + (z - 0.2)**2 <= 1 for (x, y, z) in p] expected_mask = [(b1 and b2) for (b1, b2) in zip(m1, m2)] self.assertEqual(expected_mask, g.dimensions[0].mask.tolist())
def test_simple_mask_alternating(self): x = LineGenerator("x", "mm", -1.0, 1.0, 5, alternate=True) y = LineGenerator("y", "mm", -1.0, 1.0, 5, alternate=True) r = CircularROI([0.5, 0], 1) e = ROIExcluder([r], ["x", "y"]) g = CompoundGenerator([y, x], [e], []) g.prepare() reverse = False p = [] for y in range_(-2, 3): if reverse: p += [(x / 2., y / 2.) for x in range_(2, -3, -1)] else: p += [(x / 2., y / 2.) for x in range_(-2, 3)] reverse = not reverse expected_mask = [(x - 0.5)**2 + y**2 <= 1**2 for (x, y) in p] self.assertEqual(expected_mask, g.dimensions[0].mask.tolist())
def test_alternating_with_region(self): y = LineGenerator("y", "mm", 1, 5, 5, True) x = LineGenerator("x", "mm", 1, 5, 5, True) r1 = CircularROI([3, 3], 1.5) e1 = ROIExcluder([r1], ["y", "x"]) g = CompoundGenerator([y, x], [e1], []) g.prepare() expected = [] x_f = True for y in range_(1, 6): r = range_(1, 6) if x_f else range(5, 0, -1) x_f = not x_f for x in r: expected.append({"y":float(y), "x":float(x)}) expected = [p for p in expected if ((p["x"]-3)**2 + (p["y"]-3)**2 <= 1.5**2)] expected_idx = [[xy] for xy in range_(len(expected))] points = list(g.iterator()) self.assertEqual(expected, [p.positions for p in points]) self.assertEqual(expected_idx, [p.indexes for p in points]) self.assertEqual((len(expected),), g.shape)
def test_get_point(self): x = LineGenerator("x", "mm", -1., 1, 5, False) y = LineGenerator("y", "mm", -1., 1, 5, False) z = LineGenerator("z", "mm", -1., 1, 5, False) r = CircularROI([0., 0.], 1) e = ROIExcluder([r], ["x", "y"]) g = CompoundGenerator([z, y, x], [e], []) g.prepare() points = [g.get_point(n) for n in range(0, g.size)] pos = [p.positions for p in points] idx = [p.indexes for p in points] xy_expected = [(x/2., y/2.) for y in range_(-2, 3) for x in range_(-2, 3)] xy_expected = [(x, y) for (x, y) in xy_expected if x*x + y*y <= 1] expected = [{"x":x, "y":y, "z":z/2.} for z in range_(-2, 3) for (x, y) in xy_expected] self.assertEqual(expected, pos) expected_idx = [[z, xy] for z in range_(5) for xy in range_(len(xy_expected))] self.assertEqual(expected_idx, idx)