Virtual Testbed
Ship dynamics simulator for extreme conditions
guile/grid.cc
1 #include <vtestbed/config/real_type.hh>
2 #include <vtestbed/core/grid.hh>
3 #include <vtestbed/guile/base.hh>
4 #include <vtestbed/guile/grid.hh>
5 #include <vtestbed/guile/macros.hh>
6 
7 namespace {
8  SCM type;
9  SCM kw_min, kw_max, kw_npoints, kw_nsegments;
10  SCM kw_begin_index, kw_end_index;
11  const char* grid_goops = R"(
12 (use-modules (oop goops))
13 (define-method (write (grid <grid>) port) (display (grid->string grid) port))
14 )";
15 }
16 
17 namespace vtb {
18 
19  namespace guile {
20 
21  template <int N>
22  class Grid_wrapper {
23 
24  public:
26  const int dimensions = N;
27 
28  Grid_wrapper() = default;
29 
30  Grid_wrapper(SCM min, SCM max, SCM npoints, SCM nsegments, SCM begin, SCM end) {
31  this->min(min);
32  this->max(max);
33  if (is_bound(begin)) { this->begin(begin); }
34  else { grid.begin() = VTB_REAL_TYPE{}; }
35  if (is_bound(end)) { this->end(end); }
36  else if (is_bound(npoints)) { this->num_points(npoints); }
37  else { this->num_segments(nsegments); }
38  }
39 
40  SCM min() {
41  SCM ret = SCM_EOL;
42  for (int i=N-1; i>=0; --i) {
43  ret = scm_cons(to_scm(grid.lbound(i)), ret);
44  }
45  return ret;
46  }
47 
48  SCM max() {
49  SCM ret = SCM_EOL;
50  for (int i=N-1; i>=0; --i) {
51  ret = scm_cons(to_scm(grid.ubound(i)), ret);
52  }
53  return ret;
54  }
55 
56  SCM begin() {
57  SCM ret = SCM_EOL;
58  for (int i=N-1; i>=0; --i) {
59  ret = scm_cons(to_scm(grid.begin(i)), ret);
60  }
61  return ret;
62  }
63 
64  SCM end() {
65  SCM ret = SCM_EOL;
66  for (int i=N-1; i>=0; --i) {
67  ret = scm_cons(to_scm(grid.end(i)), ret);
68  }
69  return ret;
70  }
71 
72  void min(SCM min) {
73  for (int i=0; i<N; ++i) {
74  grid.lbound(i) = scm_to_double(scm_car(min));
75  min = scm_cdr(min);
76  }
77  }
78 
79  void max(SCM max) {
80  for (int i=0; i<N; ++i) {
81  grid.ubound(i) = scm_to_double(scm_car(max));
82  max = scm_cdr(max);
83  }
84  }
85 
86  void begin(SCM begin) {
87  for (int i=0; i<N; ++i) {
88  grid.begin(i) = scm_to_int(scm_car(begin));
89  begin = scm_cdr(begin);
90  }
91  }
92 
93  void end(SCM end) {
94  for (int i=0; i<N; ++i) {
95  grid.end(i) = scm_to_int(scm_car(end));
96  end = scm_cdr(end);
97  }
98  }
99 
100  void num_points(SCM npoints) {
101  for (int i=0; i<N; ++i) {
102  grid.end(i) = grid.begin(i) + scm_to_int(scm_car(npoints));
103  npoints = scm_cdr(npoints);
104  }
105  }
106 
107  void num_segments(SCM nsegments) {
108  for (int i=0; i<N; ++i) {
109  grid.end(i) = grid.begin(i) + 1+scm_to_int(scm_car(nsegments));
110  nsegments = scm_cdr(nsegments);
111  }
112  }
113 
114  SCM select(SCM indices) {
115  SCM min = SCM_EOL;
116  SCM max = SCM_EOL;
117  SCM begin = SCM_EOL;
118  SCM end = SCM_EOL;
119  while (indices != SCM_EOL) {
120  int i = scm_to_int(scm_car(indices));
121  min = scm_cons(to_scm(grid.lbound(i)), min);
122  max = scm_cons(to_scm(grid.ubound(i)), max);
123  begin = scm_cons(to_scm(grid.begin(i)), begin);
124  end = scm_cons(to_scm(grid.end(i)), end);
125  indices = scm_cdr(indices);
126  }
127  min = scm_reverse(min);
128  max = scm_reverse(max);
129  begin = scm_reverse(begin);
130  end = scm_reverse(end);
131  return scm_call(scm_variable_ref(scm_c_lookup("make-grid")),
132  kw_min, min, kw_max, max,
133  kw_begin_index, begin, kw_end_index, end,
134  SCM_UNDEFINED);
135  }
136 
137  SCM compact() const {
138  auto* wrapper = allocate_pointerless<Grid_wrapper>("grid");
139  wrapper->grid = this->grid;
140  wrapper->grid.compact();
141  return scm_make_foreign_object_2(::type, wrapper,
142  reinterpret_cast<void*>(size_t(dimensions)));
143  }
144 
145  SCM to_string() const {
146  std::stringstream tmp;
147  tmp << this->grid;
148  return to_scm(tmp.str());
149  }
150 
151  };
152 
153  template <int N> inline Grid_wrapper<N>*
154  get_grid_wrapper(SCM object) {
155  return reinterpret_cast<Grid_wrapper<N>*>(scm_foreign_object_ref(object, 0));
156  }
157 
158  inline size_t
159  get_dimensions(SCM object) {
160  return reinterpret_cast<size_t>(scm_foreign_object_ref(object, 1));
161  }
162 
169  SCM make_grid(SCM rest) {
170  SCM min = SCM_UNDEFINED, max = SCM_UNDEFINED, npoints = SCM_UNDEFINED,
171  nsegments = SCM_UNDEFINED, begin = SCM_UNDEFINED, end = SCM_UNDEFINED;
172  scm_c_bind_keyword_arguments("make-grid", rest,
173  scm_t_keyword_arguments_flags{},
174  kw_min, &min, kw_max, &max,
175  kw_npoints, &npoints, kw_nsegments, &nsegments,
176  kw_begin_index, &begin, kw_end_index, &end,
177  SCM_UNDEFINED);
178  if (!is_bound(min) || !is_bound(max)) {
179  throw_error("missing min/max");
180  return SCM_UNSPECIFIED;
181  }
182  if (is_bound(npoints) && is_bound(nsegments)) {
183  throw_error("both num-points and num-segments defined");
184  return SCM_UNSPECIFIED;
185  }
186  if ((is_bound(end) && (is_bound(npoints) || is_bound(nsegments)))) {
187  throw_error("use either begin-index and end-index, "
188  "or begin-index and num-points/num-segments");
189  return SCM_UNSPECIFIED;
190  }
191  if (!is_list(min) || !is_list(max) ||
192  (is_bound(npoints) && !is_list(npoints)) ||
193  (is_bound(nsegments) && !is_list(nsegments))) {
194  throw_error("min/max/num-points/num-segments is not a list");
195  return SCM_UNSPECIFIED;
196  }
197  auto dimensions = length(min);
198  if (length(max) != dimensions ||
199  (is_bound(npoints) && length(npoints) != dimensions) ||
200  (is_bound(nsegments) && length(nsegments) != dimensions) ||
201  (is_bound(begin) && length(begin) != dimensions) ||
202  (is_bound(end) && length(end) != dimensions)) {
203  throw_error("min/max/num-points/num-segments/begin-index/end-index "
204  "have different length");
205  return SCM_UNSPECIFIED;
206  }
207  void* wrapper = nullptr;
208  switch (dimensions) {
209  case 1:
210  wrapper = construct_pointerless<Grid_wrapper<1>>(
211  "grid", min, max, npoints, nsegments, begin, end);
212  break;
213  case 2:
214  wrapper = construct_pointerless<Grid_wrapper<2>>(
215  "grid", min, max, npoints, nsegments, begin, end);
216  break;
217  case 3:
218  wrapper = construct_pointerless<Grid_wrapper<3>>(
219  "grid", min, max, npoints, nsegments, begin, end);
220  break;
221  case 4:
222  wrapper = construct_pointerless<Grid_wrapper<4>>(
223  "grid", min, max, npoints, nsegments, begin, end);
224  break;
225  default: throw_error("bad no. of dimensions"); return SCM_UNSPECIFIED;
226  }
227  return scm_make_foreign_object_2(::type, wrapper,
228  reinterpret_cast<void*>(size_t(dimensions)));
229  }
230 
237  SCM grid_min(SCM object) {
238  scm_assert_foreign_object_type(::type, object);
239  switch (get_dimensions(object)) {
240  case 1: return get_grid_wrapper<1>(object)->min();
241  case 2: return get_grid_wrapper<2>(object)->min();
242  case 3: return get_grid_wrapper<3>(object)->min();
243  case 4: return get_grid_wrapper<4>(object)->min();
244  }
245  return SCM_UNSPECIFIED;
246  }
247 
254  SCM grid_max(SCM object) {
255  scm_assert_foreign_object_type(::type, object);
256  switch (get_dimensions(object)) {
257  case 1: return get_grid_wrapper<1>(object)->max();
258  case 2: return get_grid_wrapper<2>(object)->max();
259  case 3: return get_grid_wrapper<3>(object)->max();
260  case 4: return get_grid_wrapper<4>(object)->max();
261  }
262  return SCM_UNSPECIFIED;
263  }
264 
271  SCM grid_begin_index(SCM object) {
272  scm_assert_foreign_object_type(::type, object);
273  switch (get_dimensions(object)) {
274  case 1: return get_grid_wrapper<1>(object)->begin();
275  case 2: return get_grid_wrapper<2>(object)->begin();
276  case 3: return get_grid_wrapper<3>(object)->begin();
277  case 4: return get_grid_wrapper<4>(object)->begin();
278  }
279  return SCM_UNSPECIFIED;
280  }
281 
288  SCM grid_end_index(SCM object) {
289  scm_assert_foreign_object_type(::type, object);
290  switch (get_dimensions(object)) {
291  case 1: return get_grid_wrapper<1>(object)->end();
292  case 2: return get_grid_wrapper<2>(object)->end();
293  case 3: return get_grid_wrapper<3>(object)->end();
294  case 4: return get_grid_wrapper<4>(object)->end();
295  }
296  return SCM_UNSPECIFIED;
297  }
298 
305  SCM grid_select(SCM object, SCM indices) {
306  scm_assert_foreign_object_type(::type, object);
307  switch (get_dimensions(object)) {
308  case 1: return get_grid_wrapper<1>(object)->select(indices);
309  case 2: return get_grid_wrapper<2>(object)->select(indices);
310  case 3: return get_grid_wrapper<3>(object)->select(indices);
311  case 4: return get_grid_wrapper<4>(object)->select(indices);
312  }
313  return SCM_UNSPECIFIED;
314  }
315 
322  SCM grid_compact(SCM object) {
323  scm_assert_foreign_object_type(::type, object);
324  switch (get_dimensions(object)) {
325  case 1: return get_grid_wrapper<1>(object)->compact();
326  case 2: return get_grid_wrapper<2>(object)->compact();
327  case 3: return get_grid_wrapper<3>(object)->compact();
328  case 4: return get_grid_wrapper<4>(object)->compact();
329  }
330  return SCM_UNSPECIFIED;
331  }
332 
339  SCM grid_to_string(SCM object) {
340  scm_assert_foreign_object_type(::type, object);
341  switch (get_dimensions(object)) {
342  case 1: return get_grid_wrapper<1>(object)->to_string();
343  case 2: return get_grid_wrapper<2>(object)->to_string();
344  case 3: return get_grid_wrapper<3>(object)->to_string();
345  case 4: return get_grid_wrapper<4>(object)->to_string();
346  }
347  return SCM_UNSPECIFIED;
348  }
349 
350  void grid_define() {
351  kw_min = scm_from_utf8_keyword("min");
352  kw_max = scm_from_utf8_keyword("max");
353  kw_npoints = scm_from_utf8_keyword("num-points");
354  kw_nsegments = scm_from_utf8_keyword("num-segments");
355  kw_begin_index = scm_from_utf8_keyword("begin-index");
356  kw_end_index = scm_from_utf8_keyword("end-index");
357  ::type = scm_make_foreign_object_type(
358  scm_from_utf8_symbol("grid"),
359  scm_list_2(scm_from_utf8_symbol("grid"), scm_from_utf8_symbol("dimensions")),
360  nullptr);
361  scm_c_define("<grid>", ::type);
362  define_procedure("make-grid", 0, 0, 1, VTB_GUILE_1(make_grid));
363  define_procedure("grid-min", 1, 0, 0, VTB_GUILE_1(grid_min));
364  define_procedure("grid-max", 1, 0, 0, VTB_GUILE_1(grid_max));
365  define_procedure("grid-begin-index", 1, 0, 0, VTB_GUILE_1(grid_begin_index));
366  define_procedure("grid-end-index", 1, 0, 0, VTB_GUILE_1(grid_end_index));
367  define_procedure("grid-select", 2, 0, 0, VTB_GUILE_2(grid_select));
368  define_procedure("grid-compact!", 1, 0, 0, VTB_GUILE_1(grid_compact));
369  define_procedure("grid->string", 1, 0, 0, VTB_GUILE_1(grid_to_string));
370  scm_c_eval_string(grid_goops);
371  }
372 
373  }
374 
375 }
376 
377 template <class T, int N> SCM
378 vtb::guile::grid_make(const vtb::core::Grid<T,N>& grid) {
379  auto* wrapper = allocate_pointerless<Grid_wrapper<N>>("grid");
380  wrapper->grid = grid;
381  return scm_make_foreign_object_2(::type, wrapper, reinterpret_cast<void*>(size_t(N)));
382 }
383 
384 template SCM
385 vtb::guile::grid_make<VTB_REAL_TYPE,1>(const vtb::core::Grid<VTB_REAL_TYPE,1>& grid);
386 
387 template SCM
388 vtb::guile::grid_make<VTB_REAL_TYPE,2>(const vtb::core::Grid<VTB_REAL_TYPE,2>& grid);
389 
390 template SCM
391 vtb::guile::grid_make<VTB_REAL_TYPE,3>(const vtb::core::Grid<VTB_REAL_TYPE,3>& grid);
392 
393 template SCM
394 vtb::guile::grid_make<VTB_REAL_TYPE,4>(const vtb::core::Grid<VTB_REAL_TYPE,4>& grid);
SCM grid_select(SCM object, SCM indices)
Construct new grid by selecting dimensions from the existing grid.
Definition: guile/grid.cc:305
SCM make_grid(SCM rest)
Construct multidimensional rectangular grid.
Definition: guile/grid.cc:169
SCM grid_end_index(SCM object)
Get grid end index (exclusive).
Definition: guile/grid.cc:288
const int_n & end() const noexcept
End indices (exclusive).
Definition: core/grid.hh:144
SCM grid_begin_index(SCM object)
Get grid begin index (inclusive).
Definition: guile/grid.cc:271
const vec & lbound() const noexcept
Lower bound of the region.
Definition: core/grid.hh:168
SCM grid_min(SCM object)
Get grid lower bound.
Definition: guile/grid.cc:237
const int_n & begin() const noexcept
Start indices (inclusive).
Definition: core/grid.hh:120
SCM grid_to_string(SCM object)
Convert grid to human-readable string.
Definition: guile/grid.cc:339
Main namespace.
Definition: convert.hh:9
SCM grid_max(SCM object)
Get grid upper bound.
Definition: guile/grid.cc:254
const vec & ubound() const noexcept
Upper bound of the region.
Definition: core/grid.hh:190
SCM grid_compact(SCM object)
Re-index the grid to make begin index equal nought.
Definition: guile/grid.cc:322