|
1 | 1 | from copy import deepcopy |
2 | | -from functools import cached_property |
| 2 | +from functools import cached_property, reduce |
3 | 3 | from math import prod |
4 | 4 |
|
| 5 | +from pacti.contracts import PropositionalIoContract |
| 6 | + |
5 | 7 | from scenic.contracts.components import ActionComponent, BaseComponent, ComposeComponent |
6 | 8 | from scenic.contracts.contracts import ContractResult, VerificationTechnique |
7 | 9 | from scenic.syntax.compiler import NameFinder, NameSwapTransformer |
@@ -137,72 +139,119 @@ def __init__( |
137 | 139 | guarantee_decoding_map[encoding_map[((port, None))]] = port |
138 | 140 | guarantee_decoding_transformer = NameSwapTransformer(guarantee_decoding_map) |
139 | 141 |
|
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)} |
143 | 148 |
|
144 | 149 | for sub_stmt in self.sub_stmts: |
| 150 | + # Copy and encode variables for assumptions and guarantees |
145 | 151 | encoding_transformer = encoding_transformers[sub_stmt.component] |
146 | | - |
147 | | - ## Copy and encode assumptions and guarantees ## |
148 | 152 | assumptions = [deepcopy(spec) for spec in sub_stmt.assumptions] |
149 | 153 | guarantees = [deepcopy(spec) for spec in sub_stmt.guarantees] |
150 | 154 |
|
151 | 155 | for spec in assumptions + guarantees: |
152 | 156 | spec.applyAtomicTransformer(encoding_transformer) |
153 | 157 |
|
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 |
206 | 255 |
|
207 | 256 | ## Decode top level assumptions and guarantees ## |
208 | 257 | # If any assumptions are still using internal temporary variable names after decoding, then |
@@ -251,9 +300,13 @@ def tempVarName(self): |
251 | 300 | self.var_num += 1 |
252 | 301 | return var_name |
253 | 302 |
|
| 303 | + @staticmethod |
| 304 | + def isTempVar(var): |
| 305 | + return var.startswith("SCENIC_INTERNAL_VAR_") |
| 306 | + |
254 | 307 | @staticmethod |
255 | 308 | 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)} |
257 | 310 |
|
258 | 311 |
|
259 | 312 | class CompositionContractResult(ContractResult): |
|
0 commit comments