Skip to content

Commit 92871be

Browse files
committed
Working toy example
1 parent 54f4045 commit 92871be

File tree

10 files changed

+468
-22
lines changed

10 files changed

+468
-22
lines changed

examples/contracts/dev.contract

Lines changed: 211 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,25 +20,66 @@ numpy.random.seed(SEED)
2020
## Components ##
2121

2222
# Dummy Sensors components
23-
component NoisyDistanceSystem(stddev, init_seed=1, overestimate=False):
23+
component RadarDistanceSystem(stddev):
2424
""" A component that provides noisy distance to the car in front."""
2525
sensors:
2626
self.leadDist: float as sensors_distance
27+
self.lead_car_width: float as lead_car_width
2728

2829
outputs:
2930
dist: float
3031

31-
state:
32-
seed: int = init_seed
32+
body:
33+
if lead_car_width < 1.8:
34+
noise = random.gauss(sigma=stddev)
35+
else:
36+
noise = 0
37+
noisy_distance = sensors_distance + noise
38+
return {"dist": noisy_distance}
39+
40+
component LaserDistanceSystem(stddev):
41+
""" A component that provides noisy distance to the car in front."""
42+
sensors:
43+
self.leadDist: float as sensors_distance
44+
self.weather: float as weather
45+
46+
outputs:
47+
dist: float
3348

3449
body:
35-
noise = random.gauss(sigma=stddev)
36-
if overestimate:
37-
noise = abs(noise)
50+
if weather == 2 or weather == 3:
51+
noise = random.gauss(sigma=stddev)
52+
else:
53+
noise = 0
3854
noisy_distance = sensors_distance + noise
39-
state.seed = random.randint(1,1000000)
4055
return {"dist": noisy_distance}
4156

57+
component MeanDistanceFilter():
58+
inputs:
59+
dist1: float
60+
dist2: float
61+
62+
outputs:
63+
mean_dist: float
64+
65+
body:
66+
mean_dist = (dist1 + dist2)/2
67+
return {"mean_dist": mean_dist}
68+
69+
component PerceptionSystem(stddev):
70+
outputs:
71+
dist: float
72+
73+
compose:
74+
rds = RadarDistanceSystem(stddev)
75+
lds = LaserDistanceSystem(stddev)
76+
mdf = MeanDistanceFilter()
77+
78+
connect rds.dist to mdf.dist1
79+
connect lds.dist to mdf.dist2
80+
81+
connect mdf.mean_dist to dist
82+
4283
component Speedometer():
4384
""" Fetches and outputss ground truth speed."""
4485
sensors:
@@ -226,7 +267,7 @@ component CarActionControls():
226267

227268
component Car(stddev, target_dist, max_speed, min_dist, max_accel, max_brake, abs_speed_err):
228269
compose:
229-
ps = NoisyDistanceSystem(stddev)
270+
ps = PerceptionSystem(stddev)
230271
sm = Speedometer()
231272
ds = DirectionSystem()
232273
cs = ControlSystem(target_dist, max_speed, min_dist, max_accel, max_brake, abs_speed_err)
@@ -243,11 +284,44 @@ component Car(stddev, target_dist, max_speed, min_dist, max_accel, max_brake, ab
243284
connect cs.steer to cac.steer
244285

245286
## Contracts ##
246-
contract AccurateDistance(perception_distance, abs_dist_err=0.5):
287+
contract RadarManufacturerDistanceAccuracy(perception_distance, abs_dist_err=0.5):
288+
""" Contract proving that perceived distance is relatively accurate."""
289+
globals:
290+
objects
291+
workspace
292+
params
293+
294+
outputs:
295+
dist: float
296+
297+
definitions:
298+
cars = [obj for obj in objects if hasattr(obj, "isVehicle") and obj.isVehicle and obj.position is not self.position]
299+
lead_distances = {car: leadDistance(self, car, workspace.network, maxDistance=2*perception_distance) for car in cars}
300+
lead_car = sorted(cars, key=lambda x: lead_distances[x])[0]
301+
lead_dist = lead_distances[lead_car]
302+
behind_car = lead_dist <= perception_distance
303+
304+
assumptions:
305+
# Assume we are in a lane
306+
always self._lane is not None
307+
308+
# Can reliably detect cars with width greater than or equal to 1.8 meters
309+
params["lead_car_width"] >= 1.8
310+
311+
guarantees:
312+
# Guarantee that if we're behind a car (in visible range), that the reported distance
313+
# is relatively accurate.
314+
always (behind_car implies (lead_dist-abs_dist_err <= dist <= lead_dist+abs_dist_err))
315+
# Guarantee that if we are not behind a car (or out of visible range), that any reported
316+
# distance is greater than our visible range.
317+
always ((not behind_car) implies (dist > perception_distance+abs_dist_err))
318+
319+
contract LaserManufacturerDistanceAccuracy(perception_distance, abs_dist_err=0.5):
247320
""" Contract proving that perceived distance is relatively accurate."""
248321
globals:
249322
objects
250323
workspace
324+
params
251325

252326
outputs:
253327
dist: float
@@ -263,6 +337,9 @@ contract AccurateDistance(perception_distance, abs_dist_err=0.5):
263337
# Assume we are in a lane
264338
always self._lane is not None
265339

340+
# Can reliably detect cars in sunny or cloudy weather (no occluding atmospheric particles)
341+
params["weather"] == 0 or params["weather"] == 1
342+
266343
guarantees:
267344
# Guarantee that if we're behind a car (in visible range), that the reported distance
268345
# is relatively accurate.
@@ -271,6 +348,99 @@ contract AccurateDistance(perception_distance, abs_dist_err=0.5):
271348
# distance is greater than our visible range.
272349
always ((not behind_car) implies (dist > perception_distance+abs_dist_err))
273350

351+
contract AccurateDistanceKnownConds(perception_distance, abs_dist_err=0.5):
352+
""" Contract proving that perceived distance is relatively accurate outside of manufacturer spec conditions"""
353+
globals:
354+
objects
355+
workspace
356+
params
357+
358+
outputs:
359+
dist: float
360+
361+
definitions:
362+
cars = [obj for obj in objects if hasattr(obj, "isVehicle") and obj.isVehicle and obj.position is not self.position]
363+
lead_distances = {car: leadDistance(self, car, workspace.network, maxDistance=2*perception_distance) for car in cars}
364+
lead_car = sorted(cars, key=lambda x: lead_distances[x])[0]
365+
lead_dist = lead_distances[lead_car]
366+
behind_car = lead_dist <= perception_distance
367+
368+
assumptions:
369+
# Assume we are in a lane
370+
always self._lane is not None
371+
372+
(params["weather"] == 0 or params["weather"] == 1) and params["lead_car_width"] >= 1.8
373+
374+
guarantees:
375+
# Guarantee that if we're behind a car (in visible range), that the reported distance
376+
# is relatively accurate.
377+
always (behind_car implies (lead_dist-abs_dist_err <= dist <= lead_dist+abs_dist_err))
378+
379+
contract AccurateDistanceUnknownConds(perception_distance, abs_dist_err=0.5):
380+
""" Contract proving that perceived distance is relatively accurate outside of manufacturer spec conditions"""
381+
globals:
382+
objects
383+
workspace
384+
params
385+
386+
outputs:
387+
dist: float
388+
389+
definitions:
390+
cars = [obj for obj in objects if hasattr(obj, "isVehicle") and obj.isVehicle and obj.position is not self.position]
391+
lead_distances = {car: leadDistance(self, car, workspace.network, maxDistance=2*perception_distance) for car in cars}
392+
lead_car = sorted(cars, key=lambda x: lead_distances[x])[0]
393+
lead_dist = lead_distances[lead_car]
394+
behind_car = lead_dist <= perception_distance
395+
396+
assumptions:
397+
# Assume we are in a lane
398+
always self._lane is not None
399+
400+
not ((params["weather"] == 0 or params["weather"] == 1) and params["lead_car_width"] >= 1.8)
401+
402+
guarantees:
403+
# Guarantee that if we're behind a car (in visible range), that the reported distance
404+
# is relatively accurate.
405+
always (behind_car implies (lead_dist-abs_dist_err <= dist <= lead_dist+abs_dist_err))
406+
407+
contract MeanDistanceFilterSemantics():
408+
inputs:
409+
dist1: float
410+
dist2: float
411+
412+
outputs:
413+
mean_dist: float
414+
415+
guarantees:
416+
always (mean_dist == (dist1 + dist2)/2)
417+
418+
contract AccurateDistance(perception_distance, abs_dist_err=0.5):
419+
""" Contract proving that perceived distance is relatively accurate."""
420+
globals:
421+
objects
422+
workspace
423+
params
424+
425+
outputs:
426+
dist: float
427+
428+
definitions:
429+
cars = [obj for obj in objects if hasattr(obj, "isVehicle") and obj.isVehicle and obj.position is not self.position]
430+
lead_distances = {car: leadDistance(self, car, workspace.network, maxDistance=2*perception_distance) for car in cars}
431+
lead_car = sorted(cars, key=lambda x: lead_distances[x])[0]
432+
lead_dist = lead_distances[lead_car]
433+
behind_car = lead_dist <= perception_distance
434+
435+
assumptions:
436+
# Assume we are in a lane
437+
always self._lane is not None
438+
439+
guarantees:
440+
# Guarantee that if we're behind a car (in visible range), that the reported distance
441+
# is relatively accurate.
442+
always (behind_car implies (lead_dist-abs_dist_err <= dist <= lead_dist+abs_dist_err))
443+
274444
contract AccurateSpeed():
275445
outputs:
276446
speed: float
@@ -356,8 +526,6 @@ contract KeepsDistance(perception_distance, min_dist, max_speed, abs_dist_err, a
356526
# Assume no one cuts in front us too closely
357527
always ((next lead_dist) == (lead_dist - true_relative_speed))
358528

359-
always (self.timestep == 0.1)
360-
361529
guarantees:
362530
# Guarantee that we always stay at least min_dist behind the lead car
363531
always lead_dist > min_dist
@@ -379,11 +547,41 @@ TARGET_DIST = 10
379547
# Instantiate Car component and link to object.
380548
implement "EgoCar" with Car(STDDEV, TARGET_DIST, MAX_SPEED, MIN_DIST, MAX_ACCEL, MAX_BRAKE, ABS_SPEED_ERR) as car
381549

550+
radar_accurate_distance = assume car.ps.rds satisfies RadarManufacturerDistanceAccuracy(
551+
PERCEPTION_DISTANCE,
552+
abs_dist_err=ABS_DIST_ERR)
553+
554+
laser_accurate_distance = assume car.ps.lds satisfies LaserManufacturerDistanceAccuracy(
555+
PERCEPTION_DISTANCE,
556+
abs_dist_err=ABS_DIST_ERR)
557+
558+
mean_dist_filter_sem = prove car.ps.mdf satisfies MeanDistanceFilterSemantics() \
559+
using LeanContractProof(localPath("ScenicLean/"), "MeanDistanceFilterSemantics", localPath("repl"))
560+
561+
accurate_distance_known_raw = compose over car.ps:
562+
use radar_accurate_distance
563+
use laser_accurate_distance
564+
use mean_dist_filter_sem
565+
566+
accurate_distance_known = refine accurate_distance_known_raw as AccurateDistanceKnownConds(
567+
PERCEPTION_DISTANCE,
568+
abs_dist_err=ABS_DIST_ERR) using LeanRefinementProof(localPath("ScenicLean/"), "AccurateDistanceKnownRefinement", localPath("repl"))
569+
570+
accurate_distance_unknown = test car.ps satisfies AccurateDistanceUnknownConds(
571+
PERCEPTION_DISTANCE,
572+
abs_dist_err=ABS_DIST_ERR),
573+
using SimulationTesting(scenario=ENVIRONMENT, maxSteps=600, confidence=0.95, batchSize=10, verbose=False),
574+
terminating after 30*60 seconds
575+
576+
accurate_distance = merge over car.ps:
577+
use accurate_distance_known
578+
use accurate_distance_unknown
579+
382580
accurate_distance = test car.ps satisfies AccurateDistance(
383581
PERCEPTION_DISTANCE,
384582
abs_dist_err=ABS_DIST_ERR),
385-
using SimulationTesting(scenario=ENVIRONMENT, maxSteps=6, confidence=0.95, batchSize=10, verbose=False),
386-
terminating after 100 samples
583+
using SimulationTesting(scenario=ENVIRONMENT, maxSteps=600, confidence=0.95, batchSize=10, verbose=False),
584+
terminating after 5*60 seconds
387585

388586
accurate_speed = assume car.sm satisfies AccurateSpeed()
389587

examples/contracts/highway.scenic

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ from scenic.core.type_support import toVector
1212
from scenic.contracts.utils import leadDistance
1313

1414
STARTING_DISTANCE = 5
15+
# 0 = Sunny, 1 = Cloudy, 2 = Rainy, 3 = Rainy
16+
param weather = Discrete({0: 0.5, 1: 0.2, 2: 0.2, 3: 0.1})
17+
param lead_car_width = Range(1.6, 2)
1518

1619
roads = network.roads
1720
select_road = Uniform(*roads)
@@ -25,14 +28,14 @@ behavior BrakeChecking():
2528

2629
# Set up lead and ego cars
2730
leadCar = new Car on select_lane.centerline,
28-
with behavior BrakeChecking()
31+
with behavior BrakeChecking(), with width globalParameters.lead_car_width
2932

3033

3134
class EgoCar(Car):
3235
targetDir[dynamic, final]: float(roadDirection[self.position].yaw)
3336

3437
ego = new EgoCar at roadDirection.followFrom(toVector(leadCar), -STARTING_DISTANCE, stepSize=0.1),
35-
with leadDist STARTING_DISTANCE,
38+
with leadDist STARTING_DISTANCE, with weather float(globalParameters.weather), with lead_car_width globalParameters.lead_car_width,
3639
with behavior FollowLaneBehavior(), with name "EgoCar", with timestep 0.1
3740

3841
# Create/activate monitor to store lead distance

0 commit comments

Comments
 (0)