Creating Sets¶
Learn how to describe regions in space with SetBuilders, evaluate them on a backend grid, and plot the result.
Run the Setup cell first, then each section in order. You can copy the code into your own scripts.
What you will learn¶
- What a SetBuilder is and how
out = S(impl)produces a grid array - Basic shapes:
HalfSpaceSet,AlignedBoxSet, and combinations - How to visualize results with
plot3d/plot2dhelpers
Not covered here: temporal logic (TLT), BallSet, CylinderSet.
Workflow (every example)¶
| Step | Action | Example |
|---|---|---|
| 1 | Describe | S = AlignedBoxSet(...) |
| 2 | Realize | out = S(impl) |
| 3 | Visualize | plot3d(out, title='...') |
Setup¶
Goal: create a backend (TVHJImpl) and small helpers (plot3d, plot2d) used in the examples below.
- The state grid is
(t, x, y, yaw)with Air3d dynamics. - When you only constrain
xandy, the set does not depend onyaw. - 3D plots use axes
(x, y, yaw)- the shape looks like a prism alongyaw.
from math import pi
import numpy as np
from pyspect import Inter, Union, Compl
from pyspect.set_builder import AlignedBoxSet, HalfSpaceSet
from pyspect.impls.static import StaticImpl
AXES = [
dict(name='x', bounds=[-5, +5], points=25),
dict(name='y', bounds=[-5, +5], points=25),
dict(name='z', bounds=[-5, +5], points=25),
]
impl = StaticImpl(AXES)
print('Axes |', ', '.join([f'{impl.axis_name(i)}: {n}'
for i, n in zip(range(impl.ndim), impl._shape)]))
Axes | x: 25, y: 25, z: 25
Warm-up: your first shape¶
Goal: run the full three-step workflow once before the detailed sections.
Takeaway: a SetBuilder is a description; S(impl) turns it into a boolean array on the grid that you can plot.
# Step 1 - describe
S = AlignedBoxSet(x=(-2, 2), y=(-1, 1))
# Step 2 - realize
out = S(impl)
# Step 3 - visualize
print('Requires |', ', '.join(S.__require__))
print('out.shape |', ', '.join([f'{s}: {n}' for s, n in zip(impl._axis_name, out.shape)]))
impl.plot(out, layout_title='AlignedBoxSet: x in [-2, 2], y in [-1, 1]')
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:142, in AppliedSet.__call__(self, impl, **m) 141 try: --> 142 func = getattr(impl, self.func) 143 except AttributeError as e: AttributeError: 'StaticImpl' object has no attribute 'box' The above exception was the direct cause of the following exception: AttributeError Traceback (most recent call last) Cell In[2], line 5 1 # Step 1 - describe 2 S = AlignedBoxSet(x=(-2, 2), y=(-1, 1)) 3 4 # Step 2 - realize ----> 5 out = S(impl) 6 7 # Step 3 - visualize 8 File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:144, in AppliedSet.__call__(self, impl, **m) 142 func = getattr(impl, self.func) 143 except AttributeError as e: --> 144 raise AttributeError(f'Impl {impl.__class__.__name__} does not support "{self.func}".') from e 146 args = [] 147 for i, arg in enumerate(self.args): AttributeError: Impl StaticImpl does not support "box".
1. HalfSpaceSet - one half-plane¶
Goal: keep points on one side of a line (one linear inequality).
Parameters:
normal- vector pointing into the allowed regionoffset- any point on the boundary lineaxes- which coordinates are constrained (herexandyonly)
Takeaway: one HalfSpaceSet = one wall / one linear constraint.
# Example A - vertical wall: x >= 0
H = HalfSpaceSet(normal=[1, 0, 0], offset=[0, 0, 0], axes=['x', 'y', 'z'])
out = H(impl)
impl.plot(out, layout_title='HalfSpaceSet: x >= 0')
# Example B - oblique wall: x >= 2y (normal [1, -2])
H = HalfSpaceSet(normal=[1, -2, 0], offset=[0, 0, 0], axes=['x', 'y', 'z'])
out = H(impl)
impl.plot(out, layout_title='HalfSpaceSet: x >= 2y')
BOX = AlignedBoxSet(x=(-2, 2), y=(-1, 1))
out = BOX(impl)
impl.plot(out, layout_title='AlignedBoxSet: x in [-2, 2], y in [-1, 1]')
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:142, in AppliedSet.__call__(self, impl, **m) 141 try: --> 142 func = getattr(impl, self.func) 143 except AttributeError as e: AttributeError: 'StaticImpl' object has no attribute 'box' The above exception was the direct cause of the following exception: AttributeError Traceback (most recent call last) Cell In[5], line 2 1 BOX = AlignedBoxSet(x=(-2, 2), y=(-1, 1)) ----> 2 out = BOX(impl) 3 impl.plot(out, layout_title='AlignedBoxSet: x in [-2, 2], y in [-1, 1]') File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:144, in AppliedSet.__call__(self, impl, **m) 142 func = getattr(impl, self.func) 143 except AttributeError as e: --> 144 raise AttributeError(f'Impl {impl.__class__.__name__} does not support "{self.func}".') from e 146 args = [] 147 for i, arg in enumerate(self.args): AttributeError: Impl StaticImpl does not support "box".
3. Combining shapes - Inter, Union, Compl¶
Goal: build richer regions from simple pieces.
| Operator | Meaning |
|---|---|
Inter(A, B) |
inside both A and B |
Union(A, B) |
inside either A or B |
Compl(A) |
outside A |
On TVHJImpl, Inter and Union take two builders at a time - nest them for three or more.
The complement operator is named Compl (not Complement).
3a. Inter - trim a box (x <= 1)¶
Takeaway: intersection = keep only points that satisfy every constraint.
base = AlignedBoxSet(x=(-3, 3), y=(-3, 3))
cut = HalfSpaceSet(normal=[-1, 0], offset=[1, 0], axes=['x', 'y']) # x <= 1
out = Inter(base, cut)(impl)
impl.plot(out, layout_title='Inter(box, x <= 1)')
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:142, in AppliedSet.__call__(self, impl, **m) 141 try: --> 142 func = getattr(impl, self.func) 143 except AttributeError as e: AttributeError: 'StaticImpl' object has no attribute 'box' The above exception was the direct cause of the following exception: AttributeError Traceback (most recent call last) File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:150, in AppliedSet.__call__(self, impl, **m) 149 try: --> 150 args.append(arg(impl, **m)) 151 except Exception as e: File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:144, in AppliedSet.__call__(self, impl, **m) 143 except AttributeError as e: --> 144 raise AttributeError(f'Impl {impl.__class__.__name__} does not support "{self.func}".') from e 146 args = [] AttributeError: Impl StaticImpl does not support "box". The above exception was the direct cause of the following exception: AttributeError Traceback (most recent call last) Cell In[6], line 3 1 base = AlignedBoxSet(x=(-3, 3), y=(-3, 3)) 2 cut = HalfSpaceSet(normal=[-1, 0], offset=[1, 0], axes=['x', 'y']) # x <= 1 ----> 3 out = Inter(base, cut)(impl) 4 impl.plot(out, layout_title='Inter(box, x <= 1)') File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:153, in AppliedSet.__call__(self, impl, **m) 151 except Exception as e: 152 E = type(e) --> 153 raise E(f'When applying "{self.func}" on argument {i}, received: {e!s}') from e 154 else: 155 args.append(arg) AttributeError: When applying "intersect" on argument 0, received: Impl StaticImpl does not support "box".
3b. Union - two separate boxes¶
Takeaway: union = a point is allowed if it lies in either region.
left = AlignedBoxSet(x=(-3, -1), y=(-2, 2))
right = AlignedBoxSet(x=(1, 3), y=(-2, 2))
out = Union(left, right)(impl)
impl.plot(out, layout_title='Union(left box, right box)')
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:142, in AppliedSet.__call__(self, impl, **m) 141 try: --> 142 func = getattr(impl, self.func) 143 except AttributeError as e: AttributeError: 'StaticImpl' object has no attribute 'box' The above exception was the direct cause of the following exception: AttributeError Traceback (most recent call last) File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:150, in AppliedSet.__call__(self, impl, **m) 149 try: --> 150 args.append(arg(impl, **m)) 151 except Exception as e: File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:144, in AppliedSet.__call__(self, impl, **m) 143 except AttributeError as e: --> 144 raise AttributeError(f'Impl {impl.__class__.__name__} does not support "{self.func}".') from e 146 args = [] AttributeError: Impl StaticImpl does not support "box". The above exception was the direct cause of the following exception: AttributeError Traceback (most recent call last) Cell In[7], line 3 1 left = AlignedBoxSet(x=(-3, -1), y=(-2, 2)) 2 right = AlignedBoxSet(x=(1, 3), y=(-2, 2)) ----> 3 out = Union(left, right)(impl) 4 impl.plot(out, layout_title='Union(left box, right box)') File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:153, in AppliedSet.__call__(self, impl, **m) 151 except Exception as e: 152 E = type(e) --> 153 raise E(f'When applying "{self.func}" on argument {i}, received: {e!s}') from e 154 else: 155 args.append(arg) AttributeError: When applying "union" on argument 0, received: Impl StaticImpl does not support "box".
3c. Compl - box with a hole¶
Takeaway: Compl removes an inner region; combine with Inter to cut holes.
outer = AlignedBoxSet(x=(-3, 3), y=(-3, 3))
obstacle = AlignedBoxSet(x=(-1, 1), y=(-1, 1))
out = Inter(outer, Compl(obstacle))(impl)
impl.plot(out, layout_title='Inter(box, Compl(obstacle)): box with hole')
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:142, in AppliedSet.__call__(self, impl, **m) 141 try: --> 142 func = getattr(impl, self.func) 143 except AttributeError as e: AttributeError: 'StaticImpl' object has no attribute 'box' The above exception was the direct cause of the following exception: AttributeError Traceback (most recent call last) File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:150, in AppliedSet.__call__(self, impl, **m) 149 try: --> 150 args.append(arg(impl, **m)) 151 except Exception as e: File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:144, in AppliedSet.__call__(self, impl, **m) 143 except AttributeError as e: --> 144 raise AttributeError(f'Impl {impl.__class__.__name__} does not support "{self.func}".') from e 146 args = [] AttributeError: Impl StaticImpl does not support "box". The above exception was the direct cause of the following exception: AttributeError Traceback (most recent call last) Cell In[8], line 3 1 outer = AlignedBoxSet(x=(-3, 3), y=(-3, 3)) 2 obstacle = AlignedBoxSet(x=(-1, 1), y=(-1, 1)) ----> 3 out = Inter(outer, Compl(obstacle))(impl) 4 impl.plot(out, layout_title='Inter(box, Compl(obstacle)): box with hole') File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:153, in AppliedSet.__call__(self, impl, **m) 151 except Exception as e: 152 E = type(e) --> 153 raise E(f'When applying "{self.func}" on argument {i}, received: {e!s}') from e 154 else: 155 args.append(arg) AttributeError: When applying "intersect" on argument 0, received: Impl StaticImpl does not support "box".
4. Slab - band between two parallel walls¶
Goal: model a corridor with fixed width along one direction.
A slab is an Inter of two opposing half-spaces. Here: -1 <= x <= 1.
Takeaway: two parallel HalfSpaceSet walls form an infinite strip / band.
SLAB = Inter(
HalfSpaceSet(normal=[1, 0, 0], offset=[-1, 0, 0], axes=['x', 'y', 'z']),
HalfSpaceSet(normal=[-1, 0, 0], offset=[1, 0, 0], axes=['x', 'y', 'z']),
)
out = SLAB(impl)
impl.plot(out, layout_title='Slab: -1 <= x <= 1')
5. 2D plot - flat slice in (x, y)¶
Goal: view the shape in the plane instead of a 3D isosurface.
Takeaway: use method='bitmap' with axes=('x', 'y') for a top-down 2D view.
out = AlignedBoxSet(x=(-2, 2), y=(-1, 1))(impl)
impl.plot(out, method='bitmap', axes=('x', 'y'), layout_title='AlignedBoxSet - 2D bitmap')
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:142, in AppliedSet.__call__(self, impl, **m) 141 try: --> 142 func = getattr(impl, self.func) 143 except AttributeError as e: AttributeError: 'StaticImpl' object has no attribute 'box' The above exception was the direct cause of the following exception: AttributeError Traceback (most recent call last) Cell In[10], line 1 ----> 1 out = AlignedBoxSet(x=(-2, 2), y=(-1, 1))(impl) 2 impl.plot(out, method='bitmap', axes=('x', 'y'), layout_title='AlignedBoxSet - 2D bitmap') File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:144, in AppliedSet.__call__(self, impl, **m) 142 func = getattr(impl, self.func) 143 except AttributeError as e: --> 144 raise AttributeError(f'Impl {impl.__class__.__name__} does not support "{self.func}".') from e 146 args = [] 147 for i, arg in enumerate(self.args): AttributeError: Impl StaticImpl does not support "box".
6. Under the hood - AlignedBoxSet as four half-spaces¶
Goal: understand how AlignedBoxSet relates to HalfSpaceSet (optional section).
A box x in [-2, 2], y in [-2, 2] is exactly the Inter of four HalfSpaceSet walls.
The numeric check below should print 0.0.
box_aligned = AlignedBoxSet(x=(-2, 2), y=(-2, 2))(impl)
box_manual = Inter(
HalfSpaceSet(normal=[1, 0], offset=[-2, 0], axes=['x', 'y']),
Inter(
HalfSpaceSet(normal=[-1, 0], offset=[2, 0], axes=['x', 'y']),
Inter(
HalfSpaceSet(normal=[0, 1], offset=[0, -2], axes=['x', 'y']),
HalfSpaceSet(normal=[0, -1], offset=[0, 2], axes=['x', 'y']),
),
),
)(impl)
diff = float(np.max(np.abs(box_aligned - box_manual)))
print(f'max |AlignedBoxSet - Inter(4 HalfSpaceSet)| = {diff:.6f}')
assert diff == 0.0, 'Expected exact match'
print('OK - AlignedBoxSet is built from half-spaces internally.')
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:142, in AppliedSet.__call__(self, impl, **m) 141 try: --> 142 func = getattr(impl, self.func) 143 except AttributeError as e: AttributeError: 'StaticImpl' object has no attribute 'box' The above exception was the direct cause of the following exception: AttributeError Traceback (most recent call last) Cell In[11], line 1 ----> 1 box_aligned = AlignedBoxSet(x=(-2, 2), y=(-2, 2))(impl) 2 3 box_manual = Inter( 4 HalfSpaceSet(normal=[1, 0], offset=[-2, 0], axes=['x', 'y']), File ~/work/pyspect/pyspect/src/pyspect/set_builder.py:144, in AppliedSet.__call__(self, impl, **m) 142 func = getattr(impl, self.func) 143 except AttributeError as e: --> 144 raise AttributeError(f'Impl {impl.__class__.__name__} does not support "{self.func}".') from e 146 args = [] 147 for i, arg in enumerate(self.args): AttributeError: Impl StaticImpl does not support "box".