sim_lib_numbers_tensor/implementation/
domain.rs1use std::sync::Arc;
5
6use sim_kernel::{
7 AbiVersion, DefaultFactory, Dependency, Export, Expr, Factory, Lib, LibManifest, LibTarget,
8 Linker, NumberDomain, Object, Result, Symbol, Value, Version,
9};
10use sim_lib_numbers_core::{
11 DomainNumberValueShape, NumberDomainTableSpec, domains, number_domain_table,
12};
13use sim_shape::shape_value;
14
15use super::{
16 cast::cast_symbol,
17 citizen::{register_tensor_value_class, tensor_value_class_symbol},
18 execution::tensor_site_symbol,
19 function::{
20 TensorFunction, index_symbol, map_symbol, mat_symbol, reshape_symbol, scalar_symbol,
21 slice_symbol, tensor_symbol, vec_symbol,
22 },
23 tensor_site::TensorSite,
24};
25
26pub fn number_domain() -> Symbol {
28 domains::tensor()
29}
30
31fn literal_class_symbol() -> Symbol {
32 domains::literal_class("tensor")
33}
34
35fn literal_instance_shape_symbol() -> Symbol {
36 Symbol::qualified(literal_class_symbol().to_string(), "instance-shape")
37}
38
39fn value_shape_symbol() -> Symbol {
40 sim_lib_numbers_core::value_shape_symbol(&number_domain())
41}
42
43#[sim_citizen_derive::non_citizen(
44 reason = "numbers/tensor number-domain marker; reconstruct by loading the tensor number lib",
45 kind = "marker",
46 descriptor = "numbers/tensor"
47)]
48struct TensorNumberDomain;
49
50impl NumberDomain for TensorNumberDomain {
51 fn symbol(&self) -> Symbol {
52 number_domain()
53 }
54
55 fn parse_priority(&self) -> i32 {
56 -200
57 }
58
59 fn parse_literal(&self, _cx: &mut sim_kernel::Cx, _text: &str) -> Result<Option<Value>> {
60 Ok(None)
61 }
62
63 fn encode_literal(
64 &self,
65 _cx: &mut sim_kernel::Cx,
66 _value: Value,
67 ) -> Result<Option<sim_kernel::NumberLiteral>> {
68 Ok(None)
69 }
70}
71
72impl Object for TensorNumberDomain {
73 fn display(&self, _cx: &mut sim_kernel::Cx) -> Result<String> {
74 Ok("#<number-domain numbers/tensor>".to_owned())
75 }
76
77 fn as_any(&self) -> &dyn std::any::Any {
78 self
79 }
80}
81
82impl sim_kernel::ObjectCompat for TensorNumberDomain {
83 fn class(&self, cx: &mut sim_kernel::Cx) -> Result<sim_kernel::ClassRef> {
84 sim_lib_numbers_core::number_domain_class_stub(cx)
85 }
86 fn as_expr(&self, _cx: &mut sim_kernel::Cx) -> Result<Expr> {
87 Ok(Expr::Symbol(number_domain()))
88 }
89 fn as_table(&self, cx: &mut sim_kernel::Cx) -> Result<Value> {
90 let literal_class = cx
91 .registry()
92 .class_by_symbol(&literal_class_symbol())
93 .cloned()
94 .unwrap_or(cx.factory().symbol(literal_class_symbol())?);
95 let instance_shape = cx
96 .registry()
97 .shape_by_symbol(&literal_instance_shape_symbol())
98 .cloned()
99 .unwrap_or(cx.factory().symbol(literal_instance_shape_symbol())?);
100 let value_shape = cx
101 .registry()
102 .shape_by_symbol(&value_shape_symbol())
103 .cloned()
104 .unwrap_or(cx.factory().symbol(value_shape_symbol())?);
105 number_domain_table(
106 cx,
107 NumberDomainTableSpec::new(
108 number_domain(),
109 "tensor",
110 "value-only",
111 -200,
112 literal_class,
113 instance_shape,
114 value_shape,
115 ),
116 )
117 }
118 fn as_number_domain(&self) -> Option<&dyn NumberDomain> {
119 Some(self)
120 }
121}
122
123struct TensorLiteralShape;
124
125impl sim_shape::Shape for TensorLiteralShape {
126 fn check_value(
127 &self,
128 _cx: &mut sim_kernel::Cx,
129 _value: Value,
130 ) -> Result<sim_shape::ShapeMatch> {
131 Ok(sim_shape::ShapeMatch::reject(
132 "numbers/tensor has no parsed literal surface".to_owned(),
133 ))
134 }
135
136 fn check_expr(&self, _cx: &mut sim_kernel::Cx, _expr: &Expr) -> Result<sim_shape::ShapeMatch> {
137 Ok(sim_shape::ShapeMatch::reject(
138 "numbers/tensor has no parsed literal surface".to_owned(),
139 ))
140 }
141
142 fn describe(&self, _cx: &mut sim_kernel::Cx) -> Result<sim_shape::ShapeDoc> {
143 Ok(sim_shape::ShapeDoc::new("TensorLiteral")
144 .with_detail("placeholder literal shape for the numbers/tensor domain")
145 .with_detail("tensor values are constructed by functions rather than parsed literals"))
146 }
147}
148
149#[sim_citizen_derive::non_citizen(
150 reason = "numbers/tensor literal class marker; tensor values use the numbers/Tensor citizen descriptor",
151 kind = "marker",
152 descriptor = "numbers/Tensor"
153)]
154struct TensorLiteralClass;
155
156impl Object for TensorLiteralClass {
157 fn display(&self, _cx: &mut sim_kernel::Cx) -> Result<String> {
158 Ok(format!("#<class {}>", literal_class_symbol()))
159 }
160
161 fn as_any(&self) -> &dyn std::any::Any {
162 self
163 }
164}
165
166impl sim_kernel::ObjectCompat for TensorLiteralClass {
167 fn class(&self, cx: &mut sim_kernel::Cx) -> Result<sim_kernel::ClassRef> {
168 if let Some(value) = cx
169 .registry()
170 .class_by_symbol(&Symbol::qualified("core", "Class"))
171 {
172 return Ok(value.clone());
173 }
174 DefaultFactory.class_stub(
175 sim_kernel::CORE_CLASS_CLASS_ID,
176 Symbol::qualified("core", "Class"),
177 )
178 }
179 fn as_expr(&self, _cx: &mut sim_kernel::Cx) -> Result<Expr> {
180 Ok(Expr::Symbol(literal_class_symbol()))
181 }
182}
183
184pub struct TensorNumbersLib;
192
193impl TensorNumbersLib {
194 pub fn new() -> Self {
198 Self
199 }
200}
201
202impl Default for TensorNumbersLib {
203 fn default() -> Self {
204 Self::new()
205 }
206}
207
208impl Lib for TensorNumbersLib {
209 fn manifest(&self) -> LibManifest {
210 LibManifest {
211 id: number_domain(),
212 version: Version(env!("CARGO_PKG_VERSION").to_owned()),
213 abi: AbiVersion { major: 0, minor: 1 },
214 target: LibTarget::HostRegistered,
215 requires: Vec::<Dependency>::new(),
216 capabilities: Vec::new(),
217 exports: vec![
218 Export::NumberDomain {
219 symbol: number_domain(),
220 number_domain_id: None,
221 },
222 Export::Class {
223 symbol: literal_class_symbol(),
224 class_id: None,
225 },
226 Export::Class {
227 symbol: tensor_value_class_symbol(),
228 class_id: None,
229 },
230 Export::Shape {
231 symbol: literal_instance_shape_symbol(),
232 shape_id: None,
233 },
234 Export::Shape {
235 symbol: value_shape_symbol(),
236 shape_id: None,
237 },
238 export_function(tensor_symbol()),
239 export_function(scalar_symbol()),
240 export_function(vec_symbol()),
241 export_function(mat_symbol()),
242 export_function(index_symbol()),
243 export_function(reshape_symbol()),
244 export_function(slice_symbol()),
245 export_function(map_symbol()),
246 export_function(cast_symbol()),
247 Export::Site {
248 symbol: tensor_site_symbol(),
249 runtime_id: None,
250 },
251 ],
252 }
253 }
254
255 fn load(&self, _cx: &mut sim_kernel::LoadCx, linker: &mut Linker<'_>) -> Result<()> {
256 linker.number_domain_value(
257 number_domain(),
258 DefaultFactory
259 .opaque(Arc::new(TensorNumberDomain))
260 .expect("tensor domain should be boxable"),
261 )?;
262 linker.class_value(
263 literal_class_symbol(),
264 DefaultFactory
265 .opaque(Arc::new(TensorLiteralClass))
266 .expect("tensor literal class should be boxable"),
267 )?;
268 register_tensor_value_class(linker)?;
269 linker.shape_value(
270 literal_instance_shape_symbol(),
271 shape_value(
272 literal_instance_shape_symbol(),
273 Arc::new(TensorLiteralShape),
274 ),
275 )?;
276 linker.shape_value(
277 value_shape_symbol(),
278 shape_value(
279 value_shape_symbol(),
280 Arc::new(DomainNumberValueShape::new(
281 number_domain(),
282 "TensorValue",
283 [
284 "number value in the numbers/tensor domain",
285 "accepts tensor-shaped collections of scalar number cells",
286 ],
287 )),
288 ),
289 )?;
290
291 for symbol in [
292 tensor_symbol(),
293 scalar_symbol(),
294 vec_symbol(),
295 mat_symbol(),
296 index_symbol(),
297 reshape_symbol(),
298 slice_symbol(),
299 map_symbol(),
300 cast_symbol(),
301 ] {
302 linker.function_value(
303 symbol.clone(),
304 DefaultFactory
305 .opaque(Arc::new(TensorFunction { symbol }))
306 .expect("tensor function should be boxable"),
307 )?;
308 }
309 linker.site_value(
310 tensor_site_symbol(),
311 DefaultFactory
312 .opaque(Arc::new(TensorSite::local_cpu()))
313 .expect("tensor site should be boxable"),
314 )?;
315 Ok(())
316 }
317}
318
319fn export_function(symbol: Symbol) -> Export {
320 Export::Function {
321 symbol,
322 function_id: None,
323 }
324}