def test_arithmetic(): a = Varying(base_time=2, slope=3, base=5) b = Varying(base_time=7, slope=11, base=13) add = a + b assert add._base_time == a._base_time assert a(20) + b(20) == add(20) assert a(30) + b(30) == add(30) sub = a - b assert add._base_time == a._base_time assert a(20) - b(20) == sub(20) assert a(30) - b(30) == sub(30) neg = -a assert neg._base_time == a._base_time assert a(20) == -neg(20) assert a(30) == -neg(30) offset1 = a + 2 offset2 = 2 + a assert add._base_time == a._base_time assert a(20) + 2 == offset1(20) == offset2(20) assert a(30) + 2 == offset1(30) == offset2(30) dif1 = a - 2 dif2 = 2 - a assert add._base_time == a._base_time assert a(20) - 2 == dif1(20) == -dif2(20) assert a(30) - 2 == dif1(30) == -dif2(30) double1 = a * 2 double2 = 2 * a assert double1._base_time == a._base_time assert double2._base_time == a._base_time assert double1(20) == double2(20) == a(20) * 2 assert double1(30) == double2(30) == a(30) * 2 half = a / 2 assert half._base_time == a._base_time assert half(20) == a(20) / 2 assert half(30) == a(30) / 2 with pytest.raises(TypeError): _ = Varying.T + 'test' with pytest.raises(TypeError): _ = 'test' + Varying.T with pytest.raises(TypeError): _ = 'test' - Varying.T with pytest.raises(TypeError): _ = Varying.T - 'test' with pytest.raises(TypeError): _ = Varying.T * 'test' with pytest.raises(TypeError): _ = 'test' * Varying.T with pytest.raises(TypeError): _ = Varying.T / 'test'
def __init__( self, *, id: int, radius: Union[int, float, Varying], source: Union[None, int, float, complex] = None, blossom_children: Optional[List['CircleFillRegion']] = None, ): self.id = id self.source = None if source is None else complex(source) self.radius = Varying(radius) self.blossom_children = blossom_children
def test_zero_intercept(): assert Varying.T.zero_intercept() == 0 assert (Varying.T + 5).zero_intercept() == -5 assert (-Varying.T * 2 + 5).zero_intercept() == 2.5 assert (-Varying.T * 0 + 5).zero_intercept() is None assert Varying(base_time=5, base=3, slope=2).zero_intercept() == 3.5 assert (Varying.T * 0).zero_intercept() is None
def create_blossom(self, contained_region_ids: List[int]) -> int: k = self._next_region_id self._next_region_id += 1 blossom_region = GraphFillRegion(id=k) blossom_region.radius = Varying(base_time=self.time, slope=1) blossom_region.blossom_children = [] self._region_data_map[k] = blossom_region for i in contained_region_ids: region = self._region_data_map[i] del self._region_data_map[i] blossom_region.blossom_children.append(region) region.radius = region.radius.then_slope_at( time_of_change=self.time, new_slope=0) for loc in region.area: blossom_region.area.add(loc) loc_data = self._loc_data(loc) loc_data.mile_markers.append( MileMarker( blossom_region, -loc_data.local_radius()(self.time), )) self._reschedule_events_for_region(blossom_region) # Rescheduling the blossom region fixed location schedules, but not # child region schedules. Fix them now. for child in blossom_region.blossom_children: for ev in list(child.schedule_map.values()): ev.invalidate() return k
def test_scalar(): with pytest.raises(TypeError): _ = int(Varying(slope=1)) with pytest.raises(TypeError): _ = float(Varying(slope=1)) with pytest.raises(TypeError): _ = complex(Varying(slope=1)) assert float(Varying(2)) == 2 assert int(Varying(2)) == 2 assert complex(Varying(2)) == 2 assert isinstance(float(Varying(2)), float) assert isinstance(int(Varying(2)), int) assert isinstance(complex(Varying(2)), complex)
def create_region(self, location: complex) -> int: k = self._next_region_id self._next_region_id += 1 self.regions[k] = CircleFillRegion(source=complex(location), id=k, radius=Varying(base_time=self.time, slope=1)) return k
def test_init(): z = Varying() assert z._base_time == 0 assert z._base == 0 assert z.slope == 0 assert z(0) == 0 assert z(1) == 0 z = Varying(base=2, base_time=3, slope=5) assert z._base_time == 3 assert z._base == 2 assert z.slope == 5 assert z(0) == -13 assert z(1) == -8 z = Varying(z) assert z._base_time == 3 assert z._base == 2 assert z.slope == 5 assert z(0) == -13 assert z(1) == -8
def __init__( self, *, id: int, source: Optional[TLocation] = None, radius: Union[int, float, Varying] = Varying.T, blossom_children: Optional[Iterable['GraphFillRegion']] = None, ): self.id = id self.source = source self.area: Set[TLocation] = set() self.radius = Varying(radius) self.blossom_children: Optional[List['GraphFillRegion', ...]] = ( None if blossom_children is None else list(blossom_children)) self.schedule_map: Dict[int, TentativeEvent] = {}
def create_blossom(self, contained_region_ids: List[int]) -> int: regions = [] for i in contained_region_ids: regions.append(self.regions[i]) del self.regions[i] for r in regions: r.radius = r.radius.then_slope_at(time_of_change=self.time, new_slope=0) k = self._next_region_id self._next_region_id += 1 self.regions[k] = CircleFillRegion(id=k, blossom_children=regions, radius=Varying(base_time=self.time, slope=1)) return k
def local_radius(self) -> Varying: if self.mile_markers: marker = self.mile_markers[-1] return marker.region.radius - marker.distance_from_region_center return Varying(0)
class CircleFillRegion: def __init__( self, *, id: int, radius: Union[int, float, Varying], source: Union[None, int, float, complex] = None, blossom_children: Optional[List['CircleFillRegion']] = None, ): self.id = id self.source = None if source is None else complex(source) self.radius = Varying(radius) self.blossom_children = blossom_children def _value_equality_values_(self): return self.id, self.source, self.radius, self.blossom_children def iter_all_circles(self) -> Iterator['CircleFillRegion']: if self.blossom_children is not None: for child in self.blossom_children: yield from (child + self.radius).iter_all_circles() if self.source is not None: yield self def __add__(self, other: Varying) -> 'CircleFillRegion': return CircleFillRegion( source=self.source, blossom_children=self.blossom_children, id=self.id, radius=self.radius + other, ) def implosion_time(self) -> Optional[float]: if self.radius.slope >= 0: return None return self.radius.zero_intercept() def distance_from_at(self, other: 'CircleFillRegion', time: float) -> float: if self.source is None or other.source is None: return min( a.distance_from_at(b, time) for a in self.iter_all_circles() for b in other.iter_all_circles()) assert isinstance(time, (int, float)) r0 = self.radius(time) r1 = other.radius(time) return abs(self.source - other.source) - r1 - r0 def collision_time(self, other: 'CircleFillRegion') -> Optional[float]: if self.source is None or other.source is None: times = [ a.collision_time(b) for a in self.iter_all_circles() for b in other.iter_all_circles() ] return min([t for t in times if t is not None], default=None) approach_speed = self.radius.slope + other.radius.slope if approach_speed <= 0: return None base_time = self.radius._base_time distance = self.distance_from_at(other, base_time) return base_time + distance / approach_speed def draw(self, *, time: float, screen, color: Optional[Tuple[int, int, int]] = None, scale: float = 1): # coverage: ignore import pygame if color is None: if self.radius.slope == 0: color = (0, 255, 0) elif self.radius.slope > 0: color = (255, 0, 0) else: color = (255, 255, 0) if self.source is not None: x = self.source.real * scale y = self.source.imag * scale r = self.radius(time) * scale pygame.draw.circle(screen, color, (int(x), int(y)), int(math.ceil(r))) else: for child in self.iter_all_circles(): child.draw(time=time, screen=screen, color=color, scale=scale) # Child regions darker. r, g, b = color darken = 0.75 color = int(r * darken), int(g * darken), int(b * darken) for child in self.blossom_children: child.draw(time=time, screen=screen, color=color, scale=scale) def __repr__(self): return f'VaryingCircle(id={self.id!r}, center={self.source!r}, radius={self.radius!r})'
def test_normal_progression(): def assert_process_event(*expected_commands: Any): event = fill.next_event() mwpm.process_event(event) assert fill.recorded_commands == list(expected_commands) fill.recorded_commands.clear() fill = RecordingFlooder(CircleFlooder()) mwpm = Mwpm(flooder=fill) mwpm.add_region(fill.create_region(100)) mwpm.add_region(fill.create_region(101)) mwpm.add_region(fill.create_region(200)) mwpm.add_region(fill.create_region(202)) mwpm.add_region(fill.create_region(300)) fill.recorded_commands.clear() # Pair ups. assert_process_event( ('next_event', RegionHitRegionEvent(region1=0, region2=1, time=0.5)), ('set_region_growth', 0, 0), ('set_region_growth', 1, 0), ) assert_process_event( ('next_event', RegionHitRegionEvent(region1=2, region2=3, time=1)), ('set_region_growth', 2, 0), ('set_region_growth', 3, 0), ) # Alternating tree starts. assert_process_event( ('next_event', RegionHitRegionEvent(region1=3, region2=4, time=97)), ('set_region_growth', 3, -1), ('set_region_growth', 2, +1), ) # Alternating tree turns into a blossom. assert_process_event( ('next_event', RegionHitRegionEvent(region1=2, region2=4, time=98)), ('create_blossom', (2, 3, 4), 5), ) assert fill.sub_flooder.regions == { 0: CircleFillRegion(id=0, source=100, radius=0.5), 1: CircleFillRegion(id=1, source=101, radius=0.5), 5: CircleFillRegion( id=5, radius=Varying(base_time=98, slope=1), blossom_children=[ CircleFillRegion(id=2, source=200, radius=2), CircleFillRegion(id=3, source=202, radius=0), CircleFillRegion(id=4, source=300, radius=98), ], ), } assert_process_event( ('next_event', RegionHitRegionEvent(region1=1, region2=5, time=194.5)), ('set_region_growth', 1, -1), ('set_region_growth', 0, +1), ) assert_process_event( ('next_event', RegionHitRegionEvent(region1=0, region2=5, time=195)), ('create_blossom', (0, 1, 5), 6), ) assert fill.next_event() is None
def test_blossom_implosion(): def assert_process_event(*expected_commands: Any): event = fill.next_event() mwpm.process_event(event) assert fill.recorded_commands == list(expected_commands) fill.recorded_commands.clear() fill = RecordingFlooder(CircleFlooder()) mwpm = Mwpm(flooder=fill) mwpm.add_region(fill.create_region(0)) mwpm.add_region(fill.create_region(1)) mwpm.add_region(fill.create_region(3)) mwpm.add_region(fill.create_region(-10)) mwpm.add_region(fill.create_region(+10)) fill.recorded_commands.clear() # Blossom created in center. assert_process_event( ('next_event', RegionHitRegionEvent(region1=0, region2=1, time=0.5)), ('set_region_growth', 0, 0), ('set_region_growth', 1, 0), ) assert_process_event( ('next_event', RegionHitRegionEvent(region1=1, region2=2, time=1.5)), ('set_region_growth', 1, -1), ('set_region_growth', 0, +1), ) assert_process_event( ('next_event', RegionHitRegionEvent(region1=0, region2=2, time=2)), ('create_blossom', (0, 1, 2), 5), ) assert fill.sub_flooder.regions == { 3: CircleFillRegion(id=3, source=-10, radius=Varying.T), 4: CircleFillRegion(id=4, source=+10, radius=Varying.T), 5: CircleFillRegion( id=5, radius=Varying(base_time=2, slope=1), blossom_children=[ CircleFillRegion(id=0, source=0, radius=1), CircleFillRegion(id=1, source=1, radius=0), CircleFillRegion(id=2, source=3, radius=2), ], ), } # Blossom becomes an inner node. assert_process_event( ('next_event', RegionHitRegionEvent(region1=4, region2=5, time=3.5)), ('set_region_growth', 4, 0), ('set_region_growth', 5, 0), ) assert_process_event( ('next_event', RegionHitRegionEvent(region1=3, region2=5, time=7.5)), ('set_region_growth', 5, -1), ('set_region_growth', 4, +1), ) # Blossom implodes. assert_process_event( ( 'next_event', BlossomImplodeEvent(blossom_region_id=5, time=9, in_out_touch_pairs=[ (0, 3), (2, 4), ]), ), ('set_region_growth', 0, -1), ('set_region_growth', 1, +1), ('set_region_growth', 2, -1), )
def test_repr(): cirq.testing.assert_equivalent_repr( Varying(base_time=2, slope=3, base=5), global_vals={'Varying': Varying} )
def test_then_slope_at(): a = Varying(base_time=2, slope=3, base=5) b = a.then_slope_at(time_of_change=7, new_slope=11) assert b._base_time == 7 assert b(7) == a(7) assert b.slope == 11
def test_equality(): eq = cirq.testing.EqualsTester() eq.add_equality_group( Varying(base_time=0, slope=1, base=0), Varying(base_time=1, slope=1, base=1), Varying(Varying(base_time=0, slope=1, base=0)), ) eq.add_equality_group( Varying(base_time=0, slope=-1, base=0), Varying(base_time=1, slope=-1, base=-1), -Varying.T, ) eq.add_equality_group( Varying(base_time=0, slope=1, base=1), Varying(base_time=1, slope=1, base=2), ) eq.add_equality_group( Varying(base_time=0, slope=0, base=50), Varying(base_time=10000, slope=0, base=50), 50, 50.0, 50.0 + 0j, ) eq.add_equality_group( Varying(base_time=0, slope=0, base=60), Varying(base_time=10000, slope=0, base=60), 60, )
def test_approximate_equality(): assert cirq.approx_eq(Varying(5), Varying(5.01), atol=0.1) assert not cirq.approx_eq(Varying(5), Varying(5.01), atol=0.001) assert cirq.approx_eq(Varying(5, slope=4), Varying(5, slope=4.01), atol=0.1) assert not cirq.approx_eq(Varying(5, slope=4), Varying(5, slope=4.01), atol=0.001) assert not cirq.approx_eq(Varying.T, 'test', atol=0.1) assert cirq.approx_eq(Varying(5), 5.001, atol=0.01) assert cirq.approx_eq(5.001, Varying(5), atol=0.01) assert not cirq.approx_eq(Varying(5), 5.001, atol=0.0001) assert not cirq.approx_eq(5.001, Varying(5), atol=0.0001)