1 import Base
2 import ../shape/core.bend as Shape
3 import ../shape/LAWS.bend as ShapeLaws
4 import ../shape/plan_proofs.bend as PlanProof
5 import ../shape/nat_proofs.bend as Nats
6 import ../storage/arith.bend as Arith
7 import ../tensor/core.bend as Core
8 import ../tensor/layout.bend as Layout
9 import ../tensor/elementwise.bend as Elementwise
10 import ../tensor/elementwise_totality.bend as Totality
11 import ../tensor/elementwise_PROOF.bend as ElementwiseProof
12 import ../tensor/elementwise_parallel_proof.bend as ParallelProof
13 import ../tensor/core_PROOF.bend as CoreProof
14 import ../tensor/transform_PROOF.bend as TransformProof
15 import ../tensor/projection_LAWS.bend as Projection
16 import ../tensor/projection_PROOF.bend as ProjectionProof
17 import ../tensor/allocation_spec.bend as Allocation
18 import ../tensor/allocation_PROOF.bend as AllocationProof
19 import ./broadcast.bend as Broadcast
20 import ./broadcast_LAWS.bend as Laws
21
22 type Holds<-P: Type> is Data:
23 Holds{-proof: P}
24
25 def Laws.keep_left_scalar(left, right):
26 {==}
27
28 def finish_retains(-input: Core.Dynamic, -right: Core.Dynamic,
29 pair: (Core.Dynamic & Core.Dynamic) & Result<&2, &1, Core.Error, Core.Dynamic>,
30 -retention: Totality.Retention) -> Laws.Retained:
31 ((left, other), result) = pair
32 match result:
33 case Fail{error}:
34 Laws.Retained{{\{Totality.Retention: l => r => l} : Totality.Retention -> Totality.SameSource(input, left)}(retention)}
35 case Done{output}:
36 Laws.Retained{{\{Totality.Retention: l => r => l} : Totality.Retention -> Totality.SameSource(input, left)}(retention)}
37
38 def zeroed_retains(input: Core.Dynamic, +target: Shape.Shape, +plan: Shape.BroadcastPlan,
39 result: Result<&2, &1, Core.Error, Core.Tensor>) -> Laws.Retained:
40 match result:
41 case Fail{error}:
42 Laws.Retained{property => {==}}
43 case Done{zeros}:
44 finish_retains(input, Core.Packed{target, zeros}, Elementwise.parallel_allocated(Elementwise.KeepLeft{}, plan, input, Core.Packed{target, zeros}, Core.new(Shape.output_shape(plan), 0.0)),
45 ElementwiseProof.parallel_allocated_retains(Elementwise.KeepLeft{}, plan, input, Core.Packed{target, zeros}, Core.new(Shape.output_shape(plan), 0.0)))
46
47 def fitted_retains(input: Core.Dynamic, +target: Shape.Shape, +plan: Shape.BroadcastPlan, same: Bool) ->
48 Laws.Retained:
49 match same:
50 case False{}:
51 Laws.Retained{property => {==}}
52 case True{}:
53 zeroed_retains(input, target, plan, Core.new(target, 0.0))
54
55 def planned_retains(input: Core.Dynamic, +target: Shape.Shape, result: Result<&2, &2, Shape.Error, Shape.BroadcastPlan>) ->
56 Laws.Retained:
57 match result:
58 case Fail{error}:
59 Laws.Retained{property => {==}}
60 case Done{+plan}:
61 fitted_retains(input, target, plan, Layout.words_same(Shape.dimensions(Shape.output_shape(plan)), Shape.dimensions(target)))
62
63 def Laws.broadcast_retains_input(input, target):
64 Core.Packed{+shape, tensor} = input
65 planned_retains(Core.Packed{shape, tensor}, target, Shape.broadcast_checked(shape, target))
66
67 type WithModel<-input: Core.Dynamic, -target: Shape.Shape, -plan: Result<&2, &2, Shape.Error, Shape.BroadcastPlan>,
68 -pair: Core.Dynamic & Result<&2, &1, Broadcast.Error, Core.Dynamic>> is Data:
69 WithModel{-mapping: Laws.MappingWith(input, target, plan, pair)}
70
71 def keep_left_expected(-right: Core.Dynamic, -right_index: U32, +left: Maybe<&2, F32>, -value: F32,
72 -present: {Some{value} == Core.checked_observe_dynamic(right, right_index) : Maybe<&2, F32>}) ->
73 Holds<{Elementwise.expected_left(Elementwise.KeepLeft{}, right, right_index, left) == left : Maybe<&2, F32>}>:
74 match left:
75 case None{}:
76 Holds{{==}}
77 case Some{+found}:
78 Holds{
79 %present : {Elementwise.expected_right(Elementwise.KeepLeft{}, found, _) == Some{found} : Maybe<&2, F32>}
80 {==}}
81
82 def keep_left_source(+plan: Shape.BroadcastPlan, +index: U32, -input: Core.Dynamic, -right: Core.Dynamic,
83 -left_index: U32, -right_index: U32, -value: F32,
84 -exact: {Done{(left_index, right_index)} == Elementwise.input_indices(plan, index) : Result<&2, &1, Core.Error, U32 & U32>},
85 -present: {Some{value} == Core.checked_observe_dynamic(right, right_index) : Maybe<&2, F32>}) ->
86 Holds<{Elementwise.expected(Elementwise.KeepLeft{}, plan, input, right, index) ==
87 Laws.source_value(input, Projection.offset_spec(plan, U32.to_nat(index))) : Maybe<&2, F32>}>:
88 Holds{Equal.trans(Maybe<&2, F32>, Elementwise.expected(Elementwise.KeepLeft{}, plan, input, right, index),
89 Projection.specified_expected(Elementwise.KeepLeft{}, input, right, Projection.offset_spec(plan, U32.to_nat(index))),
90 Laws.source_value(input, Projection.offset_spec(plan, U32.to_nat(index))),
91 Projection.expected_projection_refines(Elementwise.KeepLeft{}, plan, input, right, index),
92 %Equal.trans(Maybe<&1, U32 & U32>, Some{(left_index, right_index)}, Projection.indices_result(Elementwise.input_indices(plan, index)),
93 Projection.offset_spec(plan, U32.to_nat(index)),
94 Equal.cong(Result<&2, &1, Core.Error, U32 & U32>, Maybe<&1, U32 & U32>, Projection.indices_result,
95 Done{(left_index, right_index)}, Elementwise.input_indices(plan, index), exact),
96 Projection.input_indices_refines(plan, index)) :
97 {Projection.specified_expected(Elementwise.KeepLeft{}, input, right, _) == Laws.source_value(input, _) : Maybe<&2, F32>}
98 {\{Holds: proof => proof} : Holds<{Elementwise.expected_left(Elementwise.KeepLeft{}, right, right_index, Core.checked_observe_dynamic(input, left_index)) ==
99 Core.checked_observe_dynamic(input, left_index) : Maybe<&2, F32>}> ->
100 {Elementwise.expected_left(Elementwise.KeepLeft{}, right, right_index, Core.checked_observe_dynamic(input, left_index)) ==
101 Core.checked_observe_dynamic(input, left_index) : Maybe<&2, F32>}}(
102 keep_left_expected(right, right_index, Core.checked_observe_dynamic(input, left_index), value, present)))}
103
104 def mapped_value(+plan: Shape.BroadcastPlan, +index: U32, -input: Core.Dynamic, +target: Shape.Shape, -zeros: Core.Tensor,
105 -right_dims: {Shape.dimensions(Shape.right_shape(plan)) == Shape.dimensions(target) : List<&2, U32>},
106 -indices: ElementwiseProof.IndicesDone) ->
107 Holds<{Elementwise.expected(Elementwise.KeepLeft{}, plan, input, Core.Packed{target, zeros}, index) ==
108 Laws.source_value(input, Projection.offset_spec(plan, U32.to_nat(index))) : Maybe<&2, F32>}>:
109 Holds{{\{ElementwiseProof.IndicesDone: li => ri => exact => lb => rb =>
110 {\{TransformProof.PresentObservation: value => equal =>
111 {\{Holds: proof => proof} : Holds<{Elementwise.expected(Elementwise.KeepLeft{}, plan, input, Core.Packed{target, zeros}, index) ==
112 Laws.source_value(input, Projection.offset_spec(plan, U32.to_nat(index))) : Maybe<&2, F32>}> -> {Elementwise.expected(Elementwise.KeepLeft{}, plan, input, Core.Packed{target, zeros}, index) ==
113 Laws.source_value(input, Projection.offset_spec(plan, U32.to_nat(index))) : Maybe<&2, F32>}}(
114 keep_left_source(plan, index, input, Core.Packed{target, zeros}, li, ri, value, exact,
115 Equal.sym(Maybe<&2, F32>, Core.checked_observe(target, zeros, ri), Some{value}, equal)))} :
116 TransformProof.PresentObservation -> {Elementwise.expected(Elementwise.KeepLeft{}, plan, input, Core.Packed{target, zeros}, index) ==
117 Laws.source_value(input, Projection.offset_spec(plan, U32.to_nat(index))) : Maybe<&2, F32>}}(
118 TransformProof.present_observation(target, zeros, ri,
119 %right_dims : {Nat.is_lt(U32.to_nat(ri), Shape.logical_numel(_)) == True{} : Bool}
120 rb))} :
121 ElementwiseProof.IndicesDone -> {Elementwise.expected(Elementwise.KeepLeft{}, plan, input, Core.Packed{target, zeros}, index) ==
122 Laws.source_value(input, Projection.offset_spec(plan, U32.to_nat(index))) : Maybe<&2, F32>}}(indices)}
123
124 def output_inside(+plan: Shape.BroadcastPlan, +target: Shape.Shape, +index: U32,
125 -same_dims: {Shape.dimensions(Shape.output_shape(plan)) == Shape.dimensions(target) : List<&2, U32>},
126 -inside: Shape.LT(U32.to_nat(index), Shape.logical_numel(Shape.dimensions(target)))) ->
127 Holds<{Nat.is_lt(U32.to_nat(index), Shape.elements(Shape.output_shape(plan))) == True{} : Bool}>:
128 Holds{
129 %Equal.sym(Nat, Shape.elements(Shape.output_shape(plan)), Shape.numel(Shape.extents(Shape.output_shape(plan))), Shape.elements_exact(Shape.output_shape(plan))) :
130 {Nat.is_lt(U32.to_nat(index), _) == True{} : Bool}
131 %Equal.sym(List<&2, U32>, Shape.dimensions(Shape.output_shape(plan)), Shape.dimensions(target), same_dims) :
132 {Nat.is_lt(U32.to_nat(index), Shape.logical_numel(_)) == True{} : Bool}
133 Equal.sym(Bool, True{}, Nat.is_lt(U32.to_nat(index), Shape.logical_numel(Shape.dimensions(target))),
134 Nats.lt_true(U32.to_nat(index), Shape.logical_numel(Shape.dimensions(target)), inside))}
135
136 def finish_mapping(-input: Core.Dynamic, +target: Shape.Shape, -zeros: Core.Tensor, +plan: Shape.BroadcastPlan,
137 pair: (Core.Dynamic & Core.Dynamic) & Result<&2, &1, Core.Error, Core.Dynamic>,
138 -dims: Totality.DimensionsModel,
139 -mapping: Elementwise.MappingModel,
140 -same_dims: {Shape.dimensions(Shape.output_shape(plan)) == Shape.dimensions(target) : List<&2, U32>},
141 -right_dims: {Shape.dimensions(Shape.right_shape(plan)) == Shape.dimensions(target) : List<&2, U32>}) ->
142 WithModel:
143 ((left, right), result) = pair
144 match result:
145 case Fail{error}:
146 WithModel{Unit{}}
147 case Done{output}:
148 WithModel{(
149 Equal.trans(List<&2, U32>, Totality.dimensions(output), Shape.dimensions(Shape.output_shape(plan)), Shape.dimensions(target),
150 {\{Totality.DimensionsModel: exact => exact} : Totality.DimensionsModel ->
151 {Totality.dimensions(output) == Shape.dimensions(Shape.output_shape(plan)) : List<&2, U32>}}(dims),
152 same_dims),
153 index => inside => Equal.trans(Maybe<&2, F32>, Core.observe_dynamic(output, index),
154 Elementwise.expected(Elementwise.KeepLeft{}, plan, input, Core.Packed{target, zeros}, index),
155 Laws.source_value(input, Projection.offset_spec(plan, U32.to_nat(index))),
156 {\{Elementwise.MappingModel: prefix => prefix} :
157 Elementwise.MappingModel ->
158 Elementwise.PrefixMapping(Elementwise.KeepLeft{}, plan, input, Core.Packed{target, zeros},
159 Shape.logical_numel(Shape.dimensions(Shape.output_shape(plan))), output)}(mapping)(index)(
160 %Equal.sym(List<&2, U32>, Shape.dimensions(Shape.output_shape(plan)), Shape.dimensions(target), same_dims) :
161 Shape.LT(U32.to_nat(index), Shape.logical_numel(_))
162 inside),
163 {\{Holds: proof => proof} : Holds<{Elementwise.expected(Elementwise.KeepLeft{}, plan, input, Core.Packed{target, zeros}, index) ==
164 Laws.source_value(input, Projection.offset_spec(plan, U32.to_nat(index))) : Maybe<&2, F32>}> -> {Elementwise.expected(Elementwise.KeepLeft{}, plan, input, Core.Packed{target, zeros}, index) ==
165 Laws.source_value(input, Projection.offset_spec(plan, U32.to_nat(index))) : Maybe<&2, F32>}}(
166 mapped_value(plan, index, input, target, zeros, right_dims,
167 ElementwiseProof.indices_success(plan, index,
168 {\{Holds: proof => proof} : Holds<{Nat.is_lt(U32.to_nat(index), Shape.elements(Shape.output_shape(plan))) == True{} : Bool}> ->
169 {Nat.is_lt(U32.to_nat(index), Shape.elements(Shape.output_shape(plan))) == True{} : Bool}}(
170 output_inside(plan, target, index, same_dims, inside))))))
171 )}
172
173 def zeroed_mapping(input: Core.Dynamic, +target: Shape.Shape, +plan: Shape.BroadcastPlan,
174 result: Result<&2, &1, Core.Error, Core.Tensor>,
175 -same_dims: {Shape.dimensions(Shape.output_shape(plan)) == Shape.dimensions(target) : List<&2, U32>},
176 +left_dims: {Totality.dimensions(input) == Shape.dimensions(Shape.left_shape(plan)) : List<&2, U32>},
177 +right_dims: {Shape.dimensions(Shape.right_shape(plan)) == Shape.dimensions(target) : List<&2, U32>}) ->
178 WithModel:
179 match result:
180 case Fail{error}:
181 WithModel{Unit{}}
182 case Done{zeros}:
183 finish_mapping(input, target, zeros, plan, Elementwise.parallel_allocated(Elementwise.KeepLeft{}, plan, input, Core.Packed{target, zeros}, Core.new(Shape.output_shape(plan), 0.0)),
184 ElementwiseProof.parallel_allocated_dimensions(Elementwise.KeepLeft{}, plan, input, Core.Packed{target, zeros}, Core.new(Shape.output_shape(plan), 0.0)),
185 ParallelProof.allocated_mapping(Elementwise.KeepLeft{}, plan, input, Core.Packed{target, zeros}, Core.new(Shape.output_shape(plan), 0.0),
186 left_dims, Equal.sym(List<&2, U32>, Shape.dimensions(Shape.right_shape(plan)), Shape.dimensions(target), right_dims)),
187 same_dims, right_dims)
188
189 def fitted_mapping(input: Core.Dynamic, +target: Shape.Shape, +plan: Shape.BroadcastPlan, same: Bool,
190 -decided: {same == Layout.words_same(Shape.dimensions(Shape.output_shape(plan)), Shape.dimensions(target)) : Bool},
191 +left_dims: {Totality.dimensions(input) == Shape.dimensions(Shape.left_shape(plan)) : List<&2, U32>},
192 +right_dims: {Shape.dimensions(Shape.right_shape(plan)) == Shape.dimensions(target) : List<&2, U32>}) ->
193 WithModel:
194 match same:
195 case False{}:
196 WithModel{Unit{}}
197 case True{}:
198 zeroed_mapping(input, target, plan, Core.new(target, 0.0),
199 TransformProof.words_equal(Shape.dimensions(Shape.output_shape(plan)), Shape.dimensions(target), decided), left_dims, right_dims)
200
201 def planned_mapping(+shape: Shape.Shape, tensor: Core.Tensor, +target: Shape.Shape,
202 result: Result<&2, &2, Shape.Error, Shape.BroadcastPlan>,
203 +sources: {ShapeLaws.planned_dimensions(shape, target, result) == (Shape.dimensions(shape), Shape.dimensions(target)) : List<&2, U32> & List<&2, U32>}) ->
204 WithModel:
205 match result:
206 case Fail{error}:
207 WithModel{Unit{}}
208 case Done{+plan}:
209 fitted_mapping(Core.Packed{shape, tensor}, target, plan,
210 Layout.words_same(Shape.dimensions(Shape.output_shape(plan)), Shape.dimensions(target)), {==},
211 Equal.sym(List<&2, U32>, Shape.dimensions(Shape.left_shape(plan)), Shape.dimensions(shape),
212 Equal.cong(List<&2, U32> & List<&2, U32>, List<&2, U32>, Pair.fst(List<&2, U32>, List<&2, U32>),
213 (Shape.dimensions(Shape.left_shape(plan)), Shape.dimensions(Shape.right_shape(plan))), (Shape.dimensions(shape), Shape.dimensions(target)), sources)),
214 Equal.cong(List<&2, U32> & List<&2, U32>, List<&2, U32>, Pair.snd(List<&2, U32>, List<&2, U32>),
215 (Shape.dimensions(Shape.left_shape(plan)), Shape.dimensions(Shape.right_shape(plan))), (Shape.dimensions(shape), Shape.dimensions(target)), sources))
216
217 def Laws.broadcast_mapping(input, target):
218 Core.Packed{+shape, tensor} = input
219 Laws.MappingModel{
220 {\{WithModel: mapping => mapping} :
221 WithModel ->
222 Laws.Mapping(Core.Packed{shape, tensor}, target, Broadcast.broadcast_to(Core.Packed{shape, tensor}, target))}(
223 planned_mapping(shape, tensor, target, Shape.broadcast_checked(shape, target), PlanProof.broadcast_checked_plan(shape, target)))}
224
225 def finish_success(pair: (Core.Dynamic & Core.Dynamic) & Result<&2, &1, Core.Error, Core.Dynamic>,
226 -success: Totality.Success) -> Laws.Success:
227 ((input, zeros), result) = pair
228 match result:
229 case Fail{error}:
230 Laws.Success{Empty.absurd({False{} == True{} : Bool}, Arith.clash(
231 {\{Totality.Success: successful => successful} : Totality.Success<((input, zeros), Fail{error})> -> {False{} == True{} : Bool}}(success)))}
232 case Done{output}:
233 Laws.Success{{==}}
234
235 def zeroed_success(input: Core.Dynamic, +target: Shape.Shape, +plan: Shape.BroadcastPlan,
236 result: Result<&2, &1, Core.Error, Core.Tensor>, -done: Allocation.TensorDone,
237 -left_dims: {Totality.dimensions(input) == Shape.dimensions(Shape.left_shape(plan)) : List<&2, U32>},
238 -right_dims: {Shape.dimensions(target) == Shape.dimensions(Shape.right_shape(plan)) : List<&2, U32>}) ->
239 Laws.Success:
240 match result:
241 case Fail{error}:
242 Laws.Success{Empty.absurd({False{} == True{} : Bool},
243 {\{Allocation.TensorDone: tensor => same => Arith.clash(Equal.cong(Result<&2, &1, Core.Error, Core.Tensor>, Bool,
244 found => Result.is_done(&2, &1, Core.Error, Core.Tensor, found), Fail{error}, Done{tensor},
245 Equal.sym(Result<&2, &1, Core.Error, Core.Tensor>, Done{tensor}, Fail{error}, same)))} :
246 Allocation.TensorDone -> Empty}(done))}
247 case Done{zeros}:
248 finish_success(Elementwise.parallel_allocated(Elementwise.KeepLeft{}, plan, input, Core.Packed{target, zeros}, Core.new(Shape.output_shape(plan), 0.0)),
249 ElementwiseProof.parallel_allocated_success(Elementwise.KeepLeft{}, plan, input, Core.Packed{target, zeros}, Core.new(Shape.output_shape(plan), 0.0),
250 AllocationProof.core_new_done(Shape.output_shape(plan), 0.0)))
251
252 def fitted_success(input: Core.Dynamic, +target: Shape.Shape, +plan: Shape.BroadcastPlan, same: Bool,
253 -decided: {same == Layout.words_same(Shape.dimensions(Shape.output_shape(plan)), Shape.dimensions(target)) : Bool},
254 -truth: {Shape.dimensions(Shape.output_shape(plan)) == Shape.dimensions(target) : List<&2, U32>},
255 -left_dims: {Totality.dimensions(input) == Shape.dimensions(Shape.left_shape(plan)) : List<&2, U32>},
256 -right_dims: {Shape.dimensions(target) == Shape.dimensions(Shape.right_shape(plan)) : List<&2, U32>}) ->
257 Laws.Success:
258 match same:
259 case False{}:
260 Laws.Success{Empty.absurd({False{} == True{} : Bool},
261 Arith.clash(Equal.trans(Bool, False{}, Layout.words_same(Shape.dimensions(Shape.output_shape(plan)), Shape.dimensions(target)), True{}, decided,
262 %truth : {Layout.words_same(Shape.dimensions(Shape.output_shape(plan)), _) == True{} : Bool}
263 TransformProof.words_same_refl(Shape.dimensions(Shape.output_shape(plan))))))}
264 case True{}:
265 zeroed_success(input, target, plan, Core.new(target, 0.0), AllocationProof.core_new_done(target, 0.0), left_dims, right_dims)
266
267 def planned_success(+shape: Shape.Shape, tensor: Core.Tensor, +target: Shape.Shape,
268 result: Result<&2, &2, Shape.Error, Shape.BroadcastPlan>,
269 -sources: {ShapeLaws.planned_dimensions(shape, target, result) == (Shape.dimensions(shape), Shape.dimensions(target)) : List<&2, U32> & List<&2, U32>},
270 -built: {ShapeLaws.broadcast_built(result) == True{} : Bool},
271 -alignment: Shape.Broadcast) ->
272 Laws.Success:
273 match result:
274 case Fail{error}:
275 Laws.Success{Empty.absurd({False{} == True{} : Bool}, Arith.clash(built))}
276 case Done{+plan}:
277 fitted_success(Core.Packed{shape, tensor}, target, plan,
278 Layout.words_same(Shape.dimensions(Shape.output_shape(plan)), Shape.dimensions(target)), {==},
279 ElementwiseProof.planned_output_dimensions(shape, target, plan, Shape.dimensions(target), alignment, sources),
280 Equal.sym(List<&2, U32>, Shape.dimensions(Shape.left_shape(plan)), Shape.dimensions(shape),
281 Equal.cong(List<&2, U32> & List<&2, U32>, List<&2, U32>, Pair.fst(List<&2, U32>, List<&2, U32>),
282 (Shape.dimensions(Shape.left_shape(plan)), Shape.dimensions(Shape.right_shape(plan))), (Shape.dimensions(shape), Shape.dimensions(target)), sources)),
283 Equal.sym(List<&2, U32>, Shape.dimensions(Shape.right_shape(plan)), Shape.dimensions(target),
284 Equal.cong(List<&2, U32> & List<&2, U32>, List<&2, U32>, Pair.snd(List<&2, U32>, List<&2, U32>),
285 (Shape.dimensions(Shape.left_shape(plan)), Shape.dimensions(Shape.right_shape(plan))), (Shape.dimensions(shape), Shape.dimensions(target)), sources)))
286
287 def rank_of(+shape: Shape.Shape) -> Shape.LE(Shape.rank_dimensions(Shape.dimensions(shape)), 4n):
288 match shape:
289 case Shape.SShape{dims, size, exact, rank_bound, capacity_bound}:
290 rank_bound
291
292 def capacity_of(+shape: Shape.Shape) -> Shape.LE(Shape.logical_numel(Shape.dimensions(shape)), 1048576n):
293 match shape:
294 case Shape.SShape{dims, size, exact, rank_bound, capacity_bound}:
295 capacity_bound
296
297 def Laws.broadcast_valid_success(input, target, alignment):
298 Core.Packed{+shape, tensor} = input
299 planned_success(shape, tensor, target, Shape.broadcast_checked(shape, target), PlanProof.broadcast_checked_plan(shape, target),
300 PlanProof.broadcast_checked_complete(shape, target, Shape.dimensions(target), alignment, rank_of(target), capacity_of(target)), alignment)
301
302 def Laws.broadcast_shape_error(input, target, error, rejected):
303 Core.Packed{+shape, tensor} = input
304 %Equal.sym(Result<&2, &2, Shape.Error, Shape.BroadcastPlan>, Shape.broadcast_checked(shape, target), Fail{error}, rejected) :
305 {Broadcast.planned(Core.Packed{shape, tensor}, target, _) == (Core.Packed{shape, tensor}, Fail{Broadcast.TensorError{Core.ShapeError{error}}}) :
306 Core.Dynamic & Result<&2, &1, Broadcast.Error, Core.Dynamic>}
307 {==}
308
309 def fitted_not_target(input: Core.Dynamic, +target: Shape.Shape, +plan: Shape.BroadcastPlan, flag: Bool,
310 decided: {flag == Layout.words_same(Shape.dimensions(Shape.output_shape(plan)), Shape.dimensions(target)) : Bool},
311 differ: {Shape.dimensions(Shape.output_shape(plan)) != Shape.dimensions(target) : List<&2, U32>}) ->
312 {Broadcast.fitted(input, target, plan, flag) == (input, Fail{Broadcast.NotBroadcastable{}}) :
313 Core.Dynamic & Result<&2, &1, Broadcast.Error, Core.Dynamic>}:
314 match flag:
315 case False{}:
316 {==}
317 case True{}:
318 Empty.absurd({Broadcast.fitted(input, target, plan, True{}) == (input, Fail{Broadcast.NotBroadcastable{}}) :
319 Core.Dynamic & Result<&2, &1, Broadcast.Error, Core.Dynamic>},
320 differ(TransformProof.words_equal(Shape.dimensions(Shape.output_shape(plan)), Shape.dimensions(target), decided)))
321
322 def Laws.broadcast_not_target(input, target, plan, planned, differ):
323 Core.Packed{+shape, tensor} = input
324 %Equal.sym(Result<&2, &2, Shape.Error, Shape.BroadcastPlan>, Shape.broadcast_checked(shape, target), Done{plan}, planned) :
325 {Broadcast.planned(Core.Packed{shape, tensor}, target, _) == (Core.Packed{shape, tensor}, Fail{Broadcast.NotBroadcastable{}}) :
326 Core.Dynamic & Result<&2, &1, Broadcast.Error, Core.Dynamic>}
327 fitted_not_target(Core.Packed{shape, tensor}, target, plan,
328 Layout.words_same(Shape.dimensions(Shape.output_shape(plan)), Shape.dimensions(target)), {==}, differ)