Skip to content

Commit ae14dfa

Browse files
committed
Initial PACTI integration.
1 parent d86490d commit ae14dfa

5 files changed

Lines changed: 220 additions & 87 deletions

File tree

examples/contracts/acc.contract

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,10 +303,9 @@ contract SafeThrottleFilter(perception_distance, min_dist, min_slowdown, abs_spe
303303
definitions:
304304
# Lead speed can be roughly calculated by comparing two timesteps
305305
relative_speed = ((next dist) - dist)/self.timestep if (next(next dist)) else ((next dist) - dist)/self.timestep
306-
true_relative_speed = lead_car.speed - speed
307306

308307
stopping_time = math.ceil(speed/min_slowdown)+1
309-
rel_dist_covered = stopping_time*speed + (true_relative_speed+abs_speed_err)(max_brake-min_slowdown)*(stopping_time*(stopping_time+1))/2
308+
rel_dist_covered = stopping_time*speed + (relative_speed+abs_speed_err)(max_brake-min_slowdown)*(stopping_time*(stopping_time+1))/2
310309
buffer_dist = min_dist + rel_dist_covered
311310

312311
guarantees:

examples/contracts/dev.contract

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,10 +311,9 @@ contract SafeThrottleFilter(perception_distance, min_dist, min_slowdown, abs_spe
311311
definitions:
312312
# Lead speed can be roughly calculated by comparing two timesteps
313313
relative_speed = ((next dist) - dist)/self.timestep if (next(next dist)) else ((next dist) - dist)/self.timestep
314-
true_relative_speed = lead_car.speed - speed
315314

316315
stopping_time = math.ceil(speed/min_slowdown)+1
317-
rel_dist_covered = stopping_time*speed + (true_relative_speed+abs_speed_err)(max_brake-min_slowdown)*(stopping_time*(stopping_time+1))/2
316+
rel_dist_covered = stopping_time*speed + (relative_speed+abs_speed_err)(max_brake-min_slowdown)*(stopping_time*(stopping_time+1))/2
318317
buffer_dist = min_dist + rel_dist_covered
319318

320319
guarantees:

examples/contracts/multisensor_acc.contract

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,10 +412,9 @@ contract SafeThrottleFilter(perception_distance, min_dist, min_slowdown, abs_spe
412412
definitions:
413413
# Lead speed can be roughly calculated by comparing two timesteps
414414
relative_speed = ((next dist) - dist)/self.timestep if (next(next dist)) else ((next dist) - dist)/self.timestep
415-
true_relative_speed = lead_car.speed - speed
416415

417416
stopping_time = math.ceil(speed/min_slowdown)+1
418-
rel_dist_covered = stopping_time*speed + (true_relative_speed+abs_speed_err)(max_brake-min_slowdown)*(stopping_time*(stopping_time+1))/2
417+
rel_dist_covered = stopping_time*speed + (relative_speed+abs_speed_err)(max_brake-min_slowdown)*(stopping_time*(stopping_time+1))/2
419418
buffer_dist = min_dist + rel_dist_covered
420419

421420
guarantees:

src/scenic/contracts/composition.py

Lines changed: 112 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
from copy import deepcopy
2-
from functools import cached_property
2+
from functools import cached_property, reduce
33
from math import prod
44

5+
from pacti.contracts import PropositionalIoContract
6+
57
from scenic.contracts.components import ActionComponent, BaseComponent, ComposeComponent
68
from scenic.contracts.contracts import ContractResult, VerificationTechnique
79
from scenic.syntax.compiler import NameFinder, NameSwapTransformer
@@ -137,72 +139,119 @@ def __init__(
137139
guarantee_decoding_map[encoding_map[((port, None))]] = port
138140
guarantee_decoding_transformer = NameSwapTransformer(guarantee_decoding_map)
139141

140-
# Move through sub_stmts linearly, checking assumptions and accumulating guarantees
141-
tl_assumptions = []
142-
tl_guarantees = []
142+
# Initialize syntaxMappings
143+
syntaxMappings = {}
144+
145+
# Convert all sub_stmts to PACTI contracts and order/cluster according to sub-component
146+
stmt_groups = [[] for _ in range(len(self.sub_stmts))]
147+
stmt_group_loc = {stmt: pos for pos, stmt in enumerate(self.sub_stmts)}
143148

144149
for sub_stmt in self.sub_stmts:
150+
# Copy and encode variables for assumptions and guarantees
145151
encoding_transformer = encoding_transformers[sub_stmt.component]
146-
147-
## Copy and encode assumptions and guarantees ##
148152
assumptions = [deepcopy(spec) for spec in sub_stmt.assumptions]
149153
guarantees = [deepcopy(spec) for spec in sub_stmt.guarantees]
150154

151155
for spec in assumptions + guarantees:
152156
spec.applyAtomicTransformer(encoding_transformer)
153157

154-
#### START TODO: REPLACE THIS BLOCK WITH PACTI
155-
156-
## Split out purely external assumptions.
157-
# External assumptions can be moved to the top level contract
158-
internal_assumptions = []
159-
160-
for assumption in assumptions:
161-
names = assumption.getAtomicNames()
162-
temp_var_names = self.extractTempVars(names)
163-
if temp_var_names <= input_temp_vars:
164-
tl_assumptions.append(assumption)
165-
else:
166-
internal_assumptions.append(assumption)
167-
168-
## Attempt to discharge all internal assumptions using accumulated top-level
169-
## assumptions and guarantees.
170-
for assumption in internal_assumptions:
171-
# TACTIC 1: Discharge if we already have this assumption in our accumulated
172-
# assumptions and guarantees.
173-
if any(assumption == spec for spec in tl_assumptions + tl_guarantees):
174-
continue
175-
176-
# We couldn't prove this assumption :(
177-
## DEBUG ##
178-
print("Assumptions:")
179-
for a in tl_assumptions:
180-
print(f" {a}")
181-
182-
print("Guarantees:")
183-
for g in tl_guarantees:
184-
print(f" {g}")
185-
breakpoint()
186-
187-
## Add guarantees to accumulated top-level guarantees
188-
tl_guarantees += guarantees
189-
190-
## Simplify assumptions and guarantees, removing duplicates
191-
new_tl_assumptions = []
192-
for spec in tl_assumptions:
193-
if not any(spec == e_spec for e_spec in new_tl_assumptions):
194-
new_tl_assumptions.append(spec)
195-
tl_assumptions = new_tl_assumptions
196-
197-
new_tl_guarantees = []
198-
for spec in tl_guarantees:
199-
if not any(spec == e_spec for e_spec in new_tl_guarantees) and not any(
200-
spec == e_spec for e_spec in new_tl_assumptions
201-
):
202-
new_tl_guarantees.append(spec)
203-
tl_guarantees = new_tl_guarantees
204-
205-
#### END TODO: REPLACE THIS BLOCK WITH PACTI
158+
# Convert all assumptions and guarantees to PACTI-compatible strings
159+
pstring_assumptions = [a.toPACTIStr(syntaxMappings) for a in assumptions]
160+
pstring_guarantees = [g.toPACTIStr(syntaxMappings) for g in guarantees]
161+
162+
# Encode IO variables, create PACTI contract, and store it in the appropriate group
163+
encoded_input_vars = [
164+
encoding_transformer.name_map[i]
165+
for i in sub_stmt.component.inputs_types.keys()
166+
]
167+
encoded_output_vars = [
168+
encoding_transformer.name_map[o]
169+
for o in sub_stmt.component.outputs_types.keys()
170+
]
171+
172+
pacti_contract = PropositionalIoContract.from_strings(
173+
input_vars=encoded_input_vars,
174+
output_vars=encoded_output_vars,
175+
assumptions=pstring_assumptions,
176+
guarantees=pstring_guarantees,
177+
)
178+
179+
stmt_groups[stmt_group_loc[sub_stmt]].append(pacti_contract)
180+
181+
# Merge all groups, then compose in order.
182+
merged_contracts = [
183+
reduce(lambda x, y: x.merge(y), group) for group in stmt_groups
184+
]
185+
composed_contract = reduce(lambda x, y: x.compose(y), merged_contracts)
186+
187+
breakpoint()
188+
pass
189+
190+
# #### START TODO: REPLACE THIS BLOCK WITH PACTI
191+
# # Move through sub_stmts linearly, checking assumptions and accumulating guarantees
192+
# tl_assumptions = []
193+
# tl_guarantees = []
194+
195+
# for sub_stmt in self.sub_stmts:
196+
# encoding_transformer = encoding_transformers[sub_stmt.component]
197+
198+
# ## Copy and encode assumptions and guarantees ##
199+
# assumptions = [deepcopy(spec) for spec in sub_stmt.assumptions]
200+
# guarantees = [deepcopy(spec) for spec in sub_stmt.guarantees]
201+
202+
# for spec in assumptions + guarantees:
203+
# spec.applyAtomicTransformer(encoding_transformer)
204+
205+
# ## Split out purely external assumptions.
206+
# # External assumptions can be moved to the top level contract
207+
# internal_assumptions = []
208+
209+
# for assumption in assumptions:
210+
# names = assumption.getAtomicNames()
211+
# temp_var_names = self.extractTempVars(names)
212+
# if temp_var_names <= input_temp_vars:
213+
# tl_assumptions.append(assumption)
214+
# else:
215+
# internal_assumptions.append(assumption)
216+
217+
# ## Attempt to discharge all internal assumptions using accumulated top-level
218+
# ## assumptions and guarantees.
219+
# for assumption in internal_assumptions:
220+
# # TACTIC 1: Discharge if we already have this assumption in our accumulated
221+
# # assumptions and guarantees.
222+
# if any(assumption == spec for spec in tl_assumptions + tl_guarantees):
223+
# continue
224+
225+
# # We couldn't prove this assumption :(
226+
# ## DEBUG ##
227+
# print("Assumptions:")
228+
# for a in tl_assumptions:
229+
# print(f" {a}")
230+
231+
# print("Guarantees:")
232+
# for g in tl_guarantees:
233+
# print(f" {g}")
234+
# breakpoint()
235+
236+
# ## Add guarantees to accumulated top-level guarantees
237+
# tl_guarantees += guarantees
238+
239+
# ## Simplify assumptions and guarantees, removing duplicates
240+
# new_tl_assumptions = []
241+
# for spec in tl_assumptions:
242+
# if not any(spec == e_spec for e_spec in new_tl_assumptions):
243+
# new_tl_assumptions.append(spec)
244+
# tl_assumptions = new_tl_assumptions
245+
246+
# new_tl_guarantees = []
247+
# for spec in tl_guarantees:
248+
# if not any(spec == e_spec for e_spec in new_tl_guarantees) and not any(
249+
# spec == e_spec for e_spec in new_tl_assumptions
250+
# ):
251+
# new_tl_guarantees.append(spec)
252+
# tl_guarantees = new_tl_guarantees
253+
254+
# #### END TODO: REPLACE THIS BLOCK WITH PACTI
206255

207256
## Decode top level assumptions and guarantees ##
208257
# If any assumptions are still using internal temporary variable names after decoding, then
@@ -251,9 +300,13 @@ def tempVarName(self):
251300
self.var_num += 1
252301
return var_name
253302

303+
@staticmethod
304+
def isTempVar(var):
305+
return var.startswith("SCENIC_INTERNAL_VAR_")
306+
254307
@staticmethod
255308
def extractTempVars(var_iterable):
256-
return {var for var in var_iterable if var.startswith("SCENIC_INTERNAL_VAR_")}
309+
return {var for var in var_iterable if Composition.isTempVar(var)}
257310

258311

259312
class CompositionContractResult(ContractResult):

0 commit comments

Comments
 (0)