Kestrel Interface
Loading...
Searching...
No Matches
kest_expression.c
Go to the documentation of this file.
1#include <string.h>
2#include <stdlib.h>
3#include <stdio.h>
4#include <float.h>
5#include <math.h>
6
7#include "kest_int.h"
8
9#ifndef PRINTLINES_ALLOWED
10#define PRINTLINES_ALLOWED 0
11#endif
12
13//#define KEST_BOUNDS_CHECK_VERBOSE
14
15static const char *FNAME = "kest_expression.c";
16
19
20#define KEST_EXPRESSION_CONST(x) { \
21 .type = KEST_EXPR_CONST, \
22 .val = {.val_float = x}, \
23 .constant = 1, \
24 .cached = 1, \
25 .cached_val = x \
26};
27
39
41{
42 switch (type)
43 {
44 case KEST_EXPR_CONST: return "CONST";
45 case KEST_EXPR_NEG: return "NEG";
46 case KEST_EXPR_REF: return "REF";
47 case KEST_EXPR_ADD: return "ADD";
48 case KEST_EXPR_SUB: return "SUB";
49 case KEST_EXPR_MUL: return "MUL";
50 case KEST_EXPR_DIV: return "DIV";
51 case KEST_EXPR_ABS: return "ABS";
52 case KEST_EXPR_SQR: return "SQR";
53 case KEST_EXPR_SQRT: return "SQRT";
54 case KEST_EXPR_EXP: return "EXP";
55 case KEST_EXPR_LN: return "LN";
56 case KEST_EXPR_POW: return "POW";
57 case KEST_EXPR_SIN: return "SIN";
58 case KEST_EXPR_SINH: return "SINH";
59 case KEST_EXPR_COS: return "COS";
60 case KEST_EXPR_COSH: return "COSH";
61 case KEST_EXPR_TAN: return "TAN";
62 case KEST_EXPR_TANH: return "TANH";
63 case KEST_EXPR_ASIN: return "ASIN";
64 case KEST_EXPR_ACOS: return "ACOS";
65 case KEST_EXPR_ATAN: return "ATAN";
66 }
67
68 return "TYPE_UNKNOWN";
69}
70
104
105// Compute arity in the sense of, how many sub-expr's it uses.
106// this is used to guard accesses to the array expr->val.sub_exprs.
107// therefore, if in doubt, return 0.
108// it should not return x if expr->val.sub_expr[x-1]
109// is not a valid pointer to another expr
111{
112 if (!expr) return NO_ERROR;
113
114 // if the type is nonsense, return 0
115 if (expr->type < 0 || expr->type > KEST_EXPR_TYPE_MAX_VAL)
116 return 0;
117
118 if (expr->type == KEST_EXPR_CONST || expr->type == KEST_EXPR_REF)
119 return 0;
120
121 // arity is at least 1 if we reach this point. there are more arity 1 types than arity 2, but also arity 2 will
122 // be more common, bc arithmetic. and none of arity 3. therefore, check the arity 2 case, then return 1 otherwise
123 if (expr->type == KEST_EXPR_ADD
124 || expr->type == KEST_EXPR_SUB
125 || expr->type == KEST_EXPR_MUL
126 || expr->type == KEST_EXPR_DIV
127 || expr->type == KEST_EXPR_POW)
128 return 2;
129
130 return 1;
131}
132
134{
135 if (!expr)
136 return 1;
137
138 int ret_val = 0;
139
140 if (expr->type == KEST_EXPR_REF)
141 {
142 if (strcmp(expr->val.ref_name, "pi") == 0)
143 ret_val = 1;
144
145 if (!ret_val && strcmp(expr->val.ref_name, "e") == 0)
146 ret_val = 1;
147
148 if (!ret_val && strcmp(expr->val.ref_name, "sample_rate") == 0)
149 ret_val = 1;
150
151 if (ret_val) expr->constant = 1;
152 }
153
154 return ret_val;
155}
156
158{
159 if (!expr)
160 return 1;
161
162 return (expr->type == KEST_EXPR_CONST) || expr->constant || kest_expression_refers_constant(expr);
163}
164
166{
167 if (!expr || depth > KEST_EXPR_REC_MAX_DEPTH)
168 return 1;
169
170 //KEST_PRINTF("The expression \"%s\" ", kest_expression_to_string(expr));
171
172 int ret_val = 1;
173
174 if (expr->type == KEST_EXPR_CONST)
175 {
176 //KEST_PRINTF("is a constant.\n");
177 ret_val = 1;
178 goto detect_constants_finish;
179 }
180
181 if (expr->type == KEST_EXPR_REF)
182 {
183 //KEST_PRINTF("is a reference");
184 ret_val = kest_expression_refers_constant(expr);
185 //if (ret_val)
186 // KEST_PRINTF(" to a constant.\n");
187 //else
188 // KEST_PRINTF(" to a variable.\n");
189 goto detect_constants_finish;
190 }
191
192 int arity = kest_expression_arity(expr);
193 int sub_expr_cst;
194
195 if (arity > 0)
196 {
197 //KEST_PRINTF("has top-level arity %d. To see if it's constant, we check its %d top-level sub-expressions.\n", arity, arity);
198
199 if (!expr->val.sub_exprs)
200 {
201 //KEST_PRINTF("Unfortunately, the data is corrupted, and no sub-expressions were found.\n");
202 ret_val = 1;
203 goto detect_constants_finish;
204 }
205
206 for (int i = 0; ret_val && i < arity; i++)
207 {
208 sub_expr_cst = expr->val.sub_exprs[i] ? kest_expression_detect_constants_rec(expr->val.sub_exprs[i], depth + 1) : 1;
209
210 ret_val = ret_val && sub_expr_cst;
211 }
212 }
213
214detect_constants_finish:
215 expr->constant = ret_val;
216 //KEST_PRINTF("Therefore, \"%s\" is %sconstant.\n", kest_expression_to_string(expr), ret_val ? "" : "NOT ");
217
218 return ret_val;
219}
220
225
226static float kest_expression_evaluate_rec(kest_expression *expr, kest_expr_scope *scope, int depth)
227{
228 kest_parameter_pll *current;
230 kest_parameter *param;
231 int cmplen;
232
233 float x = 0.0;
234 float ret_val;
235
236 KEST_PRINTF("[Depth %d] kest_expression_evaluate_rec(\"%s\") in scope %p\n", depth, kest_expression_to_string(expr), scope);
237
238 if (depth > KEST_EXPR_REC_MAX_DEPTH)
239 {
240 KEST_PRINTF("kest_expression_evaluate(): Error: maximum recursion depth %d exceeded (possible dependency loop)\n", KEST_EXPR_REC_MAX_DEPTH);
241 ret_val = 0.0;
242 goto expr_compute_return;
243 }
244
245 if (!expr)
246 {
247 KEST_PRINTF("expr compute: NULL expr!\n");
248 return 0.0;
249 }
250
251 if (expr->constant && expr->cached)
252 {
253 ret_val = expr->cached_val;
254 goto expr_compute_return;
255 }
256
257 if (expr->type == KEST_EXPR_CONST)
258 {
259 ret_val = expr->val.val_float;
260 goto expr_compute_return;
261 }
262
263 if (expr->type == KEST_EXPR_REF)
264 {
265 if (!expr->val.ref_name)
266 {
267 ret_val = 0.0;
268 goto expr_compute_return;
269 }
270
271 if (strcmp(expr->val.ref_name, "pi") == 0)
272 {
273 ret_val = M_PI;
274 expr->constant = 1;
275 goto expr_compute_return;
276 }
277 else if (strcmp(expr->val.ref_name, "e") == 0)
278 {
279 ret_val = exp(1);
280 expr->constant = 1;
281 goto expr_compute_return;
282 }
283 else if (strcmp(expr->val.ref_name, "sample_rate") == 0)
284 {
285 ret_val = KEST_FPGA_SAMPLE_RATE;
286 expr->constant = 1;
287 goto expr_compute_return;
288 }
289
290 if (!scope)
291 {
292 KEST_PRINTF("Error evaluating expression \"%s\": expression refers to non-constant \"%s\", but no scope given!\n",
294 ret_val = 0.0;
295 goto expr_compute_return;
296 }
297
298 ref = kest_expr_scope_fetch(scope, expr->val.ref_name);
299
300 if (!ref)
301 {
302 KEST_PRINTF("Error evaluating expression \"%s\": expression refers to non-constant \"%s\", but it isn't found in scope!\n",
304 ret_val = 0.0;
305 goto expr_compute_return;
306 }
307
308 switch (ref->type)
309 {
311 ret_val = kest_expression_evaluate_rec(ref->val.expr, scope, depth + 1);
312 break;
313
315 if (!ref->val.param)
316 {
317 KEST_PRINTF("Error evaluating expression \"%s\": expression refers to non-constant \"%s\", but it is NULL!\n",
319 ret_val = 0.0f;
320 }
321 else
322 {
323 ret_val = ref->val.param->value;
324 }
325 break;
326
328 if (!ref->val.setting)
329 {
330 KEST_PRINTF("Error evaluating expression \"%s\": expression refers to non-constant \"%s\", but it is NULL!\n",
331 expr, expr->val.ref_name);
332 ret_val = 0.0f;
333 }
334 else
335 {
336 ret_val = (float)ref->val.setting->value;
337 }
338 break;
339
340 default:
341 KEST_PRINTF("Error evaluating expression \"%s\": expression refers to non-constant \"%s\", but it has unrecognised type %d!\n",
342 kest_expression_to_string(expr), ref->type);
343 ret_val = 0.0;
344 break;
345 }
346
347 goto expr_compute_return;
348 }
349
350 if (!expr->val.sub_exprs)
351 {
352 KEST_PRINTF("Error evaluating expression (%p): expression has arity > 0, but has no sub-expressions!\n",
353 expr->val.ref_name);
354 ret_val = 0.0;
355 goto expr_compute_return;
356 }
357
358 switch (expr->type)
359 {
360 case KEST_EXPR_NEG:
361 ret_val = -(kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1));
362 break;
363
364 case KEST_EXPR_ADD:
365 ret_val = (kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1) + kest_expression_evaluate_rec(expr->val.sub_exprs[1], scope, depth + 1));
366 break;
367
368 case KEST_EXPR_SUB:
369 ret_val = kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1) - kest_expression_evaluate_rec(expr->val.sub_exprs[1], scope, depth + 1);
370 break;
371
372 case KEST_EXPR_MUL:
373 ret_val = kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1) * kest_expression_evaluate_rec(expr->val.sub_exprs[1], scope, depth + 1);
374 break;
375
376 case KEST_EXPR_DIV:
377 x = kest_expression_evaluate_rec(expr->val.sub_exprs[1], scope, depth + 1);
378
379 if (fabsf(x) < 1e-20)
380 {
381 KEST_PRINTF("expr compute: division by zero!\n");
382 ret_val = 0.0;
383 goto expr_compute_return; // avoid division by zero by just returning 0 lol. idk. what else to do?
384 }
385
386 ret_val = kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1) / x;
387 break;
388
389 case KEST_EXPR_ABS:
390 ret_val = fabs(kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1));
391 break;
392
393 case KEST_EXPR_SQR: x = kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1); ret_val = x * x;
394 break;
395
396 case KEST_EXPR_SQRT:
397 ret_val = sqrt(kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1));
398 break;
399
400 case KEST_EXPR_EXP:
401 ret_val = exp(kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1));
402 break;
403
404 case KEST_EXPR_LN:
405 ret_val = log(kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1));
406 break;
407
408 case KEST_EXPR_POW:
409 ret_val = pow(kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1),
410 kest_expression_evaluate_rec(expr->val.sub_exprs[1], scope, depth + 1));
411 break;
412 case KEST_EXPR_SIN:
413 ret_val = sin(kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1));
414 break;
415
416 case KEST_EXPR_SINH:
417 ret_val = sinh(kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1));
418 break;
419
420 case KEST_EXPR_ASIN:
421 ret_val = asin(kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1));
422 break;
423
424 case KEST_EXPR_COS:
425 ret_val = cos(kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1));
426 break;
427
428 case KEST_EXPR_COSH:
429 ret_val = cosh(kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1));
430 break;
431
432 case KEST_EXPR_ACOS:
433 ret_val = acos(kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1));
434 break;
435
436 case KEST_EXPR_TAN:
437 ret_val = tan(kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1));
438 break;
439
440 case KEST_EXPR_TANH:
441 ret_val = tanh(kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1));
442 break;
443
444 case KEST_EXPR_ATAN:
445 ret_val = atan(kest_expression_evaluate_rec(expr->val.sub_exprs[0], scope, depth + 1));
446 break;
447 }
448
449expr_compute_return:
450
451 expr->cached = 1;
452 expr->cached_val = ret_val;
453
454 return ret_val;
455}
456
458{
459 float ret_val = kest_expression_evaluate_rec(expr, scope, 0);
460 //KEST_PRINTF("Evaluating expression; %s = %.04f\n", kest_expression_to_string(expr), ret_val);
461 return ret_val;
462}
463
465{
466 if (!expr || !param)
467 return NO_ERROR;
468
469 if (!param->name_internal)
470 return NO_ERROR;
471
472 int arity = kest_expression_arity(expr);
473
474 if (arity == 0)
475 {
476 if (expr->type != KEST_EXPR_REF)
477 return NO_ERROR;
478
479 if (!expr->val.ref_name)
480 return NO_ERROR;
481
482 return (strncmp(expr->val.ref_name, param->name_internal, strlen(expr->val.ref_name) + 1) == 0);
483 }
484
485 if (depth > KEST_EXPR_REC_MAX_DEPTH)
486 return NO_ERROR;
487
488 for (int i = 0; i < arity; i++)
489 {
490 if (kest_expression_references_param_rec(expr->val.sub_exprs[i], param, depth + 1))
491 return ERR_NULL_PTR;
492 }
493
494 return NO_ERROR;
495}
496
501
503{
504 kest_expression result;
505 result.type = KEST_EXPR_CONST;
506 result.val.val_float = v;
507 result.constant = 1;
508 result.cached = 1;
509 result.cached_val = v;
510 return result;
511}
512
514{
515 kest_expression *result = kest_alloc(sizeof(kest_expression));
516
517 if (!result) return NULL;
518
519 *result = kest_expression_const(v);
520
521 return result;
522}
523
525{
526 if (!rhs) return NULL;
527
529
530 if (!lhs) return NULL;
531
532 lhs->type = unary_type;
533 lhs->val.sub_exprs = kest_alloc(sizeof(kest_expression*) * 1);
534
535 if (!lhs->val.sub_exprs)
536 {
537 kest_free(lhs);
538 return NULL;
539 }
540
541 lhs->val.sub_exprs[0] = rhs;
542 lhs->cached = 0;
543 lhs->constant = rhs->constant;
544
545 return lhs;
546}
547
549{
550 if (!arg_1 || !arg_2) return NULL;
551
553
554 if (!bin) return NULL;
555
556 bin->type = binary_type;
557 bin->val.sub_exprs = kest_alloc(sizeof(kest_expression*) * 2);
558
559 if (!bin->val.sub_exprs)
560 {
561 kest_free(bin);
562 return NULL;
563 }
564
565 bin->val.sub_exprs[0] = arg_1;
566 bin->val.sub_exprs[1] = arg_2;
567
568 bin->cached = 0;
569 bin->constant = arg_2->constant && arg_1->constant;
570
571 return bin;
572}
573
575{
576 if (!ref_name) return NULL;
577
578 kest_expression *result = kest_alloc(sizeof(kest_expression));
579
580 if (!result) return NULL;
581
582 result->type = KEST_EXPR_REF;
583 result->val.ref_name = kest_strndup(ref_name, 64);
584
585 if (!result->val.ref_name)
586 {
587 kest_free(result);
588 return NULL;
589 }
590
591 result->constant = 0;
592 result->cached = 0;
593
594 return result;
595}
596
598{
599 kest_interval result;
600 result.a = -FLT_MAX;
601 result.b = FLT_MAX;
602 return result;
603}
604
606{
607 kest_interval result;
608 result.a = a;
609 result.b = b;
610 return result;
611}
612
614{
615 kest_interval result;
616 result.a = a;
617 result.b = FLT_MAX;
618 return result;
619}
620
622{
623 kest_interval result;
624 result.a = -FLT_MAX;
625 result.b = b;
626 return result;
627}
628
630{
631 kest_interval result;
632 result.a = v;
633 result.b = v;
634 return result;
635}
636
638{
639 kest_parameter_pll *current;
641 int found;
642
643 #ifdef KEST_BOUNDS_CHECK_VERBOSE
644 KEST_PRINTF("[Depth: %d] Computing range for expression \"%s\"...\n", depth, kest_expression_to_string(expr));
645 #endif
646
647 float p1, p2, p3, p4;
648 float z;
649 int k;
650
651 kest_interval ret;
652
653 kest_interval x_int;
654 kest_interval y_int;
655 kest_interval y_int_d;
656
657 int p_c = 0;
658
659 if (!expr)
660 {
662 goto expr_int_ret;
663 }
664 if (depth > KEST_EXPR_REC_MAX_DEPTH)
665 {
667 goto expr_int_ret;
668 }
669
670 if (expr->constant && expr->cached)
671 {
672 #ifdef KEST_BOUNDS_CHECK_VERBOSE
673 KEST_PRINTF("[Depth: %d] Expression is constant (and cached!), with known value %.3f.\n", depth, expr->cached_val);
674 #endif
676 goto expr_int_ret;
677 }
678
679 if (expr->type == KEST_EXPR_CONST)
680 {
681 #ifdef KEST_BOUNDS_CHECK_VERBOSE
682 KEST_PRINTF("[Depth: %d] Expression is constant and cached, with value %.3f.\n", depth, expr->val.val_float);
683 #endif
685 goto expr_int_ret;
686 }
687
688 if (expr->type == KEST_EXPR_REF)
689 {
690 #ifdef KEST_BOUNDS_CHECK_VERBOSE
691 KEST_PRINTF("[Depth: %d] Expression is a reference, to \"%s\". Therefore we must compute its range.\n", depth, expr->val.ref_name ? expr->val.ref_name : "(NULL)");
692 #endif
694 {
695 #ifdef KEST_BOUNDS_CHECK_VERBOSE
696 KEST_PRINTF("[Depth: %d] The referenced value is a constant,", depth);
697 #endif
698 if (expr->cached)
700 else
702 #ifdef KEST_BOUNDS_CHECK_VERBOSE
703 KEST_PRINTF(" with value %.4f\n", ret.a);
704 #endif
705 goto expr_int_ret;
706 }
707
708 if (!scope)
709 {
710 KEST_PRINTF("Error estimating expression (%p): expression refers to non-constant \"%s\", but no scope given!\n",
711 expr->val.ref_name);
713 goto expr_int_ret;
714 }
715
716 ref = kest_expr_scope_fetch(scope, expr->val.ref_name);
717
718 if (!ref)
719 {
720 KEST_PRINTF("Error estimating expression (%p): expression refers to non-constant \"%s\", but it isn't found in scope!\n",
721 expr, expr->val.ref_name);
723 goto expr_int_ret;
724 }
725
726 switch (ref->type)
727 {
729 #ifdef KEST_BOUNDS_CHECK_VERBOSE
730 KEST_PRINTF("[Depth: %d] The referred quantity is an expression, so we recurse and compute its range!\n", depth);
731 #endif
732 ret = kest_expression_compute_range_rec(ref->val.expr, scope, depth + 1);
733 break;
734
736 if (!ref->val.param)
737 {
738 #ifdef KEST_BOUNDS_CHECK_VERBOSE
739 KEST_PRINTF("The reference is to a parameter, but, ultimately, it turned up NULL!\n");
740 #endif
742 }
743 else
744 {
745 #ifdef KEST_BOUNDS_CHECK_VERBOSE
746 KEST_PRINTF("[Depth: %d] The reference is to a parameter. We compute its range.\n", depth);
747 #endif
748 if (ref->val.param->min_expr)
749 {
750 ret.a = kest_expression_evaluate_rec(ref->val.param->min_expr, scope, depth + 1);
751 }
752 else
753 {
754 ret.a = ref->val.param->min;
755 }
756 if (ref->val.param->max_expr)
757 {
758 ret.b = kest_expression_evaluate_rec(ref->val.param->max_expr, scope, depth + 1);
759 }
760 else
761 {
762 ret.b = ref->val.param->max;
763 }
764
765 #ifdef KEST_BOUNDS_CHECK_VERBOSE
766 KEST_PRINTF("[Depth: %d] Obtained parameter range [%.4f, %.4f].\n", depth, ret.a, ret.b);
767 #endif
768 }
769 break;
770
771 default:
772 KEST_PRINTF("Error evaluating expression (%p): expression refers to non-constant \"%s\", but it has unrecognised type %d!\n",
773 expr->val.ref_name, ref->type);
775 break;
776 }
777
778 goto expr_int_ret;
779 }
780
781 int arity = kest_expression_arity(expr);
782
783 if (arity == 1 && (!expr->val.sub_exprs || !expr->val.sub_exprs[0]))
784 {
786 goto expr_int_ret;
787 }
788
789 if (arity == 2 && (!expr->val.sub_exprs || !expr->val.sub_exprs[0] || !expr->val.sub_exprs[1]))
790 {
792 goto expr_int_ret;
793 }
794
795 #ifdef KEST_BOUNDS_CHECK_VERBOSE
796 KEST_PRINTF("[Depth: %d] The expression has top-level arity %d; therefore we recurse and compute ranges of its top-level sub-expressions.\n", depth, arity);
797 #endif
798
799 if (arity >= 1) x_int = kest_expression_compute_range_rec(expr->val.sub_exprs[0], scope, depth + 1);
800 if (arity > 1) y_int = kest_expression_compute_range_rec(expr->val.sub_exprs[1], scope, depth + 1);
801
802 switch (expr->type)
803 {
804 case KEST_EXPR_NEG:
805 ret = kest_interval_ab(-x_int.b, -x_int.a);
806 goto expr_int_ret;
807
808 case KEST_EXPR_ADD:
809 ret = kest_interval_ab(x_int.a + y_int.a, x_int.b + y_int.b);
810 goto expr_int_ret;
811
812 case KEST_EXPR_SQRT:
813 if (x_int.a < 0) ret.a = 0;
814 else ret.a = sqrt(x_int.a);
815
816 if (x_int.b < 0) ret.b = 0;
817 else ret.b = sqrt(x_int.b);
818
819 goto expr_int_ret;
820
821 case KEST_EXPR_LN:
822 if (x_int.a <= 0)
823 ret.a = -FLT_MAX;
824 else
825 ret.a = log(x_int.a);
826
827 if (x_int.b <= 0)
828 ret.b = -FLT_MAX;
829 else
830 ret.b = log(x_int.b);
831
832 goto expr_int_ret;
833
834 case KEST_EXPR_ASIN:
835 if (x_int.a < -1)
836 ret.a = -M_PI / 2;
837 else if (x_int.a > 1)
838 ret.a = M_PI / 2;
839 else
840 ret.a = asin(x_int.a);
841
842 if (x_int.b < -1)
843 ret.b = -M_PI / 2;
844 else if (x_int.b > 1)
845 ret.b = M_PI / 2;
846 else
847 ret.b = asin(x_int.b);
848
849 goto expr_int_ret;
850
851 case KEST_EXPR_ACOS:
852 if (x_int.b < -1) ret.a = M_PI;
853 else if (x_int.b > 1) ret.a = 0.0f;
854 else ret.a = acos(x_int.b);
855
856 if (x_int.b < -1) ret.b = M_PI;
857 else if (x_int.b > 1) ret.b = 0.0f;
858 else ret.b = acos(x_int.b);
859
860 goto expr_int_ret;
861
862 case KEST_EXPR_ATAN:
863 ret = kest_interval_ab(atan(x_int.a), atan(x_int.b));
864 goto expr_int_ret;
865
866 case KEST_EXPR_TANH:
867 ret = kest_interval_ab(tanh(x_int.a), tanh(x_int.b));
868 goto expr_int_ret;
869
870 case KEST_EXPR_SINH:
871 ret = kest_interval_ab(sinh(x_int.a), sin(x_int.b));
872 goto expr_int_ret;
873
874 case KEST_EXPR_EXP:
875 ret = kest_interval_ab(exp(x_int.a), exp(x_int.b));
876 goto expr_int_ret;
877
878 case KEST_EXPR_SUB:
879 ret = kest_interval_ab(x_int.a - y_int.b, x_int.b - y_int.a);
880 goto expr_int_ret;
881
882 case KEST_EXPR_SQR:
883 if (x_int.a < 0)
884 {
885 if (x_int.b > 0) ret.a = 0.0;
886 else ret.a = x_int.b * x_int.b;
887 }
888 else
889 {
890 ret.a = x_int.a * x_int.a;
891 }
892
893 p1 = x_int.a * x_int.a;
894 p2 = x_int.b * x_int.b;
895
896 if (p2 > p1) ret.b = p2;
897 else ret.b = p1;
898
899 goto expr_int_ret;
900
901 case KEST_EXPR_COSH:
902 if (x_int.a < 0)
903 {
904 if (x_int.b > 0) ret.a = 1.0;
905 else ret.a = cosh(x_int.b);
906 }
907 else
908 {
909 ret.a = cosh(x_int.a);
910 }
911
912 p1 = cosh(x_int.a);
913 p2 = cosh(x_int.b);
914
915 if (p2 > p1) ret.b = p2;
916 else ret.b = p1;
917
918 goto expr_int_ret;
919
920 case KEST_EXPR_ABS:
921 if (x_int.a < 0)
922 {
923 if (x_int.b > 0) ret.a = 0.0;
924 else ret.a = -x_int.b;
925 }
926 else
927 {
928 ret.a = x_int.a;
929 }
930
931 p1 = fabs(x_int.a);
932 p2 = fabs(x_int.b);
933
934 if (p2 > p1) ret.b = p2;
935 else ret.b = p1;
936
937 goto expr_int_ret;
938
939 case KEST_EXPR_MUL:
940 p1 = x_int.a * y_int.a;
941 p2 = x_int.a * y_int.b;
942 p3 = x_int.b * y_int.a;
943 p4 = x_int.b * y_int.b;
944
945 z = p1;
946 if (p2 < z) z = p2;
947 if (p3 < z) z = p3;
948 if (p4 < z) z = p4;
949
950 ret.a = z;
951
952 z = p1;
953 if (p2 > z) z = p2;
954 if (p3 > z) z = p3;
955 if (p4 > z) z = p4;
956
957 ret.b = z;
958
959 goto expr_int_ret;
960
961 case KEST_EXPR_DIV:
962 // If y crosses 0, trouble ensues
963 if (y_int.a <= 0.0f && 0.0f <= y_int.b)
964 {
965 // and x is strictly negative or strictly positive,
966 if (x_int.a > 0.0f || x_int.b < 0.0f)
967 {
968 // then the sign is that of y, can be
969 // either, and the abs can be arbitrarily
970 // large. ignore the possibility of
971 // disconnected range; our interval
972 // type cannot represent this, regardless
974 goto expr_int_ret;
975 }
976 else if (x_int.a == 0.0f && x_int.b == 0.0f)
977 {
978 // if x is identically zero, then the division
979 // vanishes wherever it is defined, so call
980 // the range {0}.
981 ret = kest_interval_singleton(0.0f);
982 goto expr_int_ret;
983 }
984 else
985 {
986 // In the final case, x can cross 0 as well.
987 // All bets are off here; possibly x *equals* y,
988 // so x / y is identically 1. However, for our
989 // purposes, we take the safest route, and call
990 // it surjective
992 goto expr_int_ret;
993 }
994 }
995
996 /*
997 * In the case that y does not cross 0,
998 * we can take the range of the four corners
999 * as we did for multiplication, but multiplying
1000 * by 1/y.
1001 */
1002
1003 // Clamp y away from 0, for safety
1004 if (y_int.a < 0.0f && y_int.a > -1e-20f) y_int.a = -1e-20f;
1005 if (y_int.a > 0.0f && y_int.a < 1e-20f) y_int.a = 1e-20f;
1006
1007 if (y_int.b < 0.0f && y_int.b > -1e-20f) y_int.b = -1e-20f;
1008 if (y_int.b > 0.0f && y_int.b < 1e-20f) y_int.b = 1e-20f;
1009
1010 y_int_d.a = (fabsf(y_int.a) < 1e-20) ? FLT_MAX : 1.0 / y_int.a;
1011 y_int_d.b = (fabsf(y_int.b) < 1e-20) ? FLT_MAX : 1.0 / y_int.b;
1012
1013 p1 = x_int.a * y_int_d.a;
1014 p2 = x_int.a * y_int_d.b;
1015 p3 = x_int.b * y_int_d.a;
1016 p4 = x_int.b * y_int_d.b;
1017
1018 z = p1;
1019 if (p2 < z) z = p2;
1020 if (p3 < z) z = p3;
1021 if (p4 < z) z = p4;
1022
1023 ret.a = z;
1024
1025 z = p1;
1026 if (p2 > z) z = p2;
1027 if (p3 > z) z = p3;
1028 if (p4 > z) z = p4;
1029
1030 ret.b = z;
1031
1032 goto expr_int_ret;
1033
1034 case KEST_EXPR_POW:
1035
1036 // Negative bases for powers cause sign nonsense.
1037 // Ignore them. Accept that results will be wrong
1038
1039 if (x_int.a < 0)
1040 x_int.a = 0;
1041 if (x_int.b < 0)
1042 x_int.b = 0;
1043
1044 if (x_int.a == 0 && x_int.b == 0)
1045 {
1046 ret = kest_interval_ab(0.0f, 1.0f);
1047 goto expr_int_ret;
1048 }
1049
1050 p1 = pow(x_int.a, y_int.a);
1051 p2 = pow(x_int.a, y_int.b);
1052 p3 = pow(x_int.b, y_int.a);
1053 p4 = pow(x_int.b, y_int.b);
1054
1055 z = p1;
1056 if (p2 < z) z = p2;
1057 if (p3 < z) z = p3;
1058 if (p4 < z) z = p4;
1059
1060 ret.a = z;
1061
1062 z = p1;
1063 if (p2 > z) z = p2;
1064 if (p3 > z) z = p3;
1065 if (p4 > z) z = p4;
1066
1067 ret.b = z;
1068
1069 goto expr_int_ret;
1070
1071 case KEST_EXPR_COS:
1072 // I am preposterously lazy and decided
1073 // to re-use the code for sin for cos,
1074 // with the arguments shifted by pi/2.
1075 // Mathematically provable to be correct
1076 // Fight me
1077 x_int.a = x_int.a + (0.5*M_PI);
1078 x_int.b = x_int.b + (0.5*M_PI);
1079 case KEST_EXPR_SIN:
1080 // If the range of x contains a whole period of sin,
1081 // the range sin(x) is the range of sin. Easy!
1082 if (x_int.b - x_int.a > (2.0*M_PI))
1083 {
1084 ret = kest_interval_ab(-1, 1);
1085 goto expr_int_ret;
1086 }
1087
1088 // Detect whether there is a minimum of sin in the interval.
1089 // minima have the form pi/2 + 2pi*k. Therefore, we compute
1090 // the smallest such number exceeding x_min by means of
1091 // computing the smallest k for which pi/2 + 2pi*k exceeds
1092 // x_min. This is gotten by looking pi/2-on from x_min,
1093 // dividing by 2pi, and rounding up.
1094 k = (int)ceilf((x_int.a + (0.5*M_PI)) / (2.0*M_PI));
1095
1096 // Then, the smallest minimum of sin exceeding x_min
1097 // is given by pi/2 + 2pi*k. It lives in the interval
1098 // [x_min, x_max] precisely when it is leq x_max,
1099 // in which case there is a minimum of sin in that interval
1100 // and therefore, the minimum of our range is -1.
1101 if (-(0.5*M_PI) + k * (2.0*M_PI) <= x_int.b)
1102 {
1103 ret.a = -1;
1104 }
1105 else
1106 {
1107 // Otherwise, sin has no local minima in the interval, and
1108 // therefore, since it is smooth, its minimum over that interval
1109 // is found at an endpoint. So, compute the values there and
1110 // take the minimum thereof.
1111 p1 = sin(x_int.a);
1112 p2 = sin(x_int.b);
1113
1114 p_c = 1;
1115
1116 if (p2 < p1) ret.a = p2;
1117 else ret.a = p1;
1118 }
1119
1120 // And we repeat the analogous logic for the maximum
1121 k = (int)ceilf((x_int.a - (0.5*M_PI)) / (2.0*M_PI));
1122
1123 if ((0.5*M_PI) + k * (2.0*M_PI) <= x_int.b)
1124 {
1125 ret.b = 1;
1126 }
1127 else
1128 {
1129 if (!p_c)
1130 {
1131 p1 = sin(x_int.a);
1132 p2 = sin(x_int.b);
1133 }
1134
1135 if (p2 > p1) ret.b = p2;
1136 else ret.b = p1;
1137 }
1138
1139 goto expr_int_ret;
1140
1141 case KEST_EXPR_TAN:
1142 // If the range of x contains a period,
1143 // then it contains a singularity of tan,
1144 // so declare the range to be \mathbb R.
1145 if (x_int.b - x_int.a >= M_PI)
1146 {
1148 }
1149 else
1150 {
1151 // ... otherwise, we can carefully detect whether there is
1152 // a singularity in the interval; since tan = sin/cos,
1153 // singularities of tan correspond to zeroes of cos,
1154 // and cos vanishes precisely when |sin| = 1. Therefore,
1155 // we can reuse the logic for detecting minima and maxima
1156 // of sine!
1157 k = (int)ceilf((x_int.a - (0.5*M_PI)) / (2.0*M_PI));
1158
1159 if ((0.5*M_PI) + k * (2.0*M_PI) <= x_int.b)
1160 {
1162 }
1163 else
1164 {
1165 k = (int)ceilf((x_int.a + M_PI/2) / (2.0*M_PI));
1166
1167 if (-(0.5*M_PI) + k * (2.0*M_PI) <= x_int.b)
1168 {
1170 }
1171 else
1172 {
1173 // Finally, if there is no singularity in the
1174 // interval, then, since tan is monotone
1175 // increasing on any connected subset of its
1176 // domain, we simply apply it.
1177 ret = kest_interval_ab(tan(x_int.a), tan(x_int.b));
1178 }
1179 }
1180 }
1181
1182 goto expr_int_ret;
1183
1184 default:
1186 goto expr_int_ret;
1187 }
1188
1189expr_int_ret:
1190 // This should never happen, but, juuuust in case...
1191 if (ret.a > ret.b)
1192 {
1193 z = ret.a;
1194 ret.a = ret.b;
1195 ret.b = z;
1196 }
1197
1198 #ifdef KEST_BOUNDS_CHECK_VERBOSE
1199 KEST_PRINTF("[Depth: %d] Therefore, the range of \"%s\" is [%.4f, %.4f].\n", depth, kest_expression_to_string(expr), ret.a, ret.b);
1200 #endif
1201
1202 return ret;
1203}
1204
1205// Just a wrapper function to call the recursive function starting from depth 0
1210
1212{
1213 if (!expr)
1214 return "";
1215
1216 switch (expr->type)
1217 {
1218 case KEST_EXPR_SQRT: return "sqrt";
1219 case KEST_EXPR_EXP: return "e^";
1220 case KEST_EXPR_LN: return "ln";
1221 case KEST_EXPR_SIN: return "sin";
1222 case KEST_EXPR_SINH: return "sinh";
1223 case KEST_EXPR_COS: return "cos";
1224 case KEST_EXPR_COSH: return "cosh";
1225 case KEST_EXPR_TAN: return "tan";
1226 case KEST_EXPR_TANH: return "tanh";
1227 case KEST_EXPR_ASIN: return "asin";
1228 case KEST_EXPR_ACOS: return "acos";
1229 case KEST_EXPR_ATAN: return "atan";
1230 default: return "";
1231 }
1232
1233 return "";
1234}
1235
1237{
1238 if (!expr)
1239 return "";
1240
1241 switch (expr->type)
1242 {
1243 case KEST_EXPR_ADD: return " + ";
1244 case KEST_EXPR_SUB: return " - ";
1245 case KEST_EXPR_DIV: return " / ";
1246 case KEST_EXPR_MUL: return " * ";
1247 case KEST_EXPR_POW: return "^";
1248 default: return "";
1249 }
1250
1251 return "";
1252}
1253
1254int kest_expression_print_rec(kest_expression *expr, char *buf, int buf_len, int depth)
1255{
1256 if (!expr || !buf)
1257 return 0;
1258
1259 int buf_pos = 0;
1260 const char *str_ptr;
1261 int len;
1262
1263 if (buf_len == 1)
1264 goto kest_expr_print_end;
1265
1266 if (buf_len < 0)
1267 return 0;
1268
1269 if (depth > KEST_EXPR_REC_MAX_DEPTH)
1270 goto kest_expr_print_end;
1271
1272 switch (kest_expression_form(expr))
1273 {
1274 default:
1276 if (expr->type == KEST_EXPR_CONST)
1277 {
1278 snprintf(buf, buf_len, "%.03f", expr->val.val_float);
1279
1280 // snprintf doesn't exaaaaccctly return the number of
1281 // characters written, so just find it myself lol
1282 buf_pos = strlen(buf);
1283 }
1284 else if (expr->type == KEST_EXPR_REF)
1285 {
1286 if (!expr->val.ref_name)
1287 {
1288 buf[buf_pos++] = '('; if (buf_len < buf_pos + 1) goto kest_expr_print_end;
1289 buf[buf_pos++] = 'n'; if (buf_len < buf_pos + 1) goto kest_expr_print_end;
1290 buf[buf_pos++] = 'u'; if (buf_len < buf_pos + 1) goto kest_expr_print_end;
1291 buf[buf_pos++] = 'l'; if (buf_len < buf_pos + 1) goto kest_expr_print_end;
1292 buf[buf_pos++] = 'l'; if (buf_len < buf_pos + 1) goto kest_expr_print_end;
1293 buf[buf_pos++] = ')';
1294 }
1295 else
1296 {
1297 while (expr->val.ref_name[buf_pos] != 0 && buf_pos < buf_len)
1298 {
1299 buf[buf_pos] = expr->val.ref_name[buf_pos];
1300 buf_pos++;
1301 }
1302 }
1303 }
1304
1305 break;
1306
1308 // Currently, there is only one unary operator with standard form. Cbf writing anything fancy
1309 buf[buf_pos++] = '-'; if (buf_len < buf_pos + 1) goto kest_expr_print_end;
1310
1311 if (expr->val.sub_exprs && expr->val.sub_exprs[0] && expr->val.sub_exprs[0]->type == KEST_EXPR_CONST && expr->val.sub_exprs[0]->val.val_float < 0)
1312 {
1313 goto bracketed_unary_sub_expr;
1314 }
1315
1316 buf_pos += kest_expression_print_rec(expr->val.sub_exprs[0], &buf[buf_pos], buf_len - buf_pos, depth + 1);
1317 break;
1318
1320 str_ptr = kest_expression_function_string(expr);
1321
1322 while (str_ptr[buf_pos] != 0 && buf_pos < buf_len)
1323 {
1324 buf[buf_pos] = str_ptr[buf_pos];
1325 buf_pos++;
1326 }
1327
1328 if (buf_len < buf_pos + 1) goto kest_expr_print_end;
1329
1330 goto bracketed_unary_sub_expr;
1331 break;
1332
1334 buf[buf_pos++] = '('; if (buf_len < buf_pos + 1) goto kest_expr_print_end;
1335 buf_pos += kest_expression_print_rec(expr->val.sub_exprs[0], &buf[buf_pos], buf_len - buf_pos, depth + 1);
1336 if (buf_len < buf_pos + 1) goto kest_expr_print_end;
1338
1339 for (int i = 0; str_ptr[i] != 0 && buf_pos < buf_len; i++)
1340 buf[buf_pos++] = str_ptr[i];
1341
1342 if (buf_len < buf_pos + 1) goto kest_expr_print_end;
1343
1344 buf_pos += kest_expression_print_rec(expr->val.sub_exprs[1], &buf[buf_pos], buf_len - buf_pos, depth + 1);
1345 if (buf_len < buf_pos + 1) goto kest_expr_print_end;
1346 buf[buf_pos++] = ')';
1347 break;
1348
1350 buf[buf_pos++] = '|'; if (buf_len < buf_pos + 1) goto kest_expr_print_end;
1351 buf_pos += kest_expression_print_rec(expr->val.sub_exprs[0], &buf[buf_pos], buf_len - buf_pos, depth + 1);
1352 if (buf_len < buf_pos + 1) goto kest_expr_print_end;
1353 buf[buf_pos++] = '|';
1354 break;
1355 }
1356
1357 goto kest_expr_print_end;
1358bracketed_unary_sub_expr:
1359 buf[buf_pos++] = '('; if (buf_len < buf_pos + 1) goto kest_expr_print_end;
1360 buf_pos += kest_expression_print_rec(expr->val.sub_exprs[0], &buf[buf_pos], buf_len - buf_pos, depth + 1);
1361 if (buf_len < buf_pos + 1) goto kest_expr_print_end;
1362 buf[buf_pos++] = ')';
1363
1364kest_expr_print_end:
1365
1366 buf[buf_pos] = 0;
1367 return buf_pos;
1368}
1369
1371
1373{
1374 if (!expr)
1375 return ERR_NULL_PTR;
1376
1377 char buf[256];
1378
1379 kest_expression_print_rec(expr, buf, 256, 0);
1380 KEST_PRINTF("%s", buf);
1381
1382 return NO_ERROR;
1383}
1384
1386{
1387 if (!expr)
1388 {
1389 expr_print_buf[0] = 0;
1390 return expr_print_buf;
1391 }
1392
1394
1395 return expr_print_buf;
1396}
void kest_free(void *ptr)
Definition kest_alloc.c:32
void * kest_alloc(size_t size)
Definition kest_alloc.c:11
char * kest_strndup(const char *str, size_t n)
Definition kest_alloc.c:73
#define NO_ERROR
#define ERR_NULL_PTR
kest_expr_scope_entry * kest_expr_scope_fetch(kest_expr_scope *scope, const char *name)
#define KEST_SCOPE_ENTRY_TYPE_PARAM
#define KEST_SCOPE_ENTRY_TYPE_EXPR
#define KEST_SCOPE_ENTRY_TYPE_SETTING
kest_interval kest_interval__b(float b)
kest_expression kest_expression_zero
int kest_expression_detect_constants(kest_expression *expr)
kest_interval kest_expression_compute_range_rec(kest_expression *expr, kest_expr_scope *scope, int depth)
const char * kest_expression_infix_operator_string(kest_expression *expr)
kest_expression kest_expression_int_max
int kest_expression_form(kest_expression *expr)
int kest_expression_references_param(kest_expression *expr, kest_parameter *param)
kest_expression * new_m_expression_reference(char *ref_name)
kest_expression * new_m_expression_const(float v)
kest_interval kest_interval_a_(float a)
int kest_expression_is_constant(kest_expression *expr)
kest_interval kest_expression_compute_range(kest_expression *expr, kest_expr_scope *scope)
char expr_print_buf[256]
int kest_expression_detect_constants_rec(kest_expression *expr, int depth)
kest_expression kest_expression_standard_gain_min
kest_expression kest_expression_pi
kest_expression kest_expression_freq_max
kest_expression kest_expression_sample_rate
int kest_expression_print_rec(kest_expression *expr, char *buf, int buf_len, int depth)
const char * kest_expression_function_string(kest_expression *expr)
int kest_expression_arity(kest_expression *expr)
char * kest_expression_type_to_str(int type)
#define KEST_EXPRESSION_CONST(x)
int kest_expression_print(kest_expression *expr)
kest_interval kest_interval_real_line()
kest_expression kest_expression_standard_gain_max
kest_expression * new_m_expression_unary(int unary_type, kest_expression *rhs)
kest_expression kest_expression_one
int kest_expression_references_param_rec(kest_expression *expr, kest_parameter *param, int depth)
const char * kest_expression_to_string(kest_expression *expr)
float kest_expression_evaluate(kest_expression *expr, kest_expr_scope *scope)
kest_expression kest_expression_int_min
kest_expression kest_expression_minus_one
kest_expression * new_m_expression_binary(int binary_type, kest_expression *arg_1, kest_expression *arg_2)
kest_interval kest_interval_singleton(float v)
kest_interval kest_interval_ab(float a, float b)
kest_expression kest_expression_e
kest_expression kest_expression_const(float v)
int kest_expression_refers_constant(kest_expression *expr)
#define KEST_EXPR_FORM_UNARY_OP
#define KEST_EXPR_ABS
#define KEST_EXPR_CONST
#define KEST_EXPR_SQR
#define KEST_EXPR_MUL
#define KEST_EXPR_EXP
#define KEST_EXPR_REC_MAX_DEPTH
#define KEST_EXPR_ATAN
#define KEST_EXPR_SUB
#define KEST_EXPR_TANH
#define KEST_EXPR_ACOS
#define KEST_EXPR_COSH
#define KEST_EXPR_SQRT
#define KEST_EXPR_ADD
#define KEST_EXPR_POW
#define KEST_EXPR_SIN
#define KEST_EXPR_FORM_UNARY_FN
#define KEST_EXPR_FORM_INFIX_OP
#define KEST_EXPR_FORM_ATOMIC
#define KEST_EXPR_ASIN
#define KEST_EXPR_NEG
#define KEST_EXPR_LN
#define KEST_EXPR_TYPE_MAX_VAL
#define KEST_EXPR_FORM_NORM
#define KEST_EXPR_SINH
#define KEST_EXPR_TAN
#define KEST_EXPR_DIV
#define KEST_EXPR_COS
#define KEST_EXPR_REF
#define KEST_FPGA_SAMPLE_RATE
Definition kest_fpga_io.h:4
#define KEST_FPGA_DATA_WIDTH
#define IMPLEMENT_LINKED_PTR_LIST(X)
#define IMPLEMENT_PTR_LIST(X)
Definition kest_list.h:339
#define KEST_STANDARD_GAIN_MIN
#define KEST_STANDARD_GAIN_MAX
#define KEST_PRINTF(...)
Definition kest_printf.h:10
int type
struct kest_expression * expr
struct kest_parameter * param
struct kest_setting * setting
union kest_expr_scope_entry::@246374331353003302125051026062066243300031256272 val
union kest_expression::@166010055114121035173062362142367362353107353142 val
struct kest_expression ** sub_exprs
struct kest_expression * min_expr
const char * name_internal
struct kest_expression * max_expr