symbolic4
expression.c
Go to the documentation of this file.
1 
2 /*
3 
4  Copyright (c) 2019 Hannes Eberhard
5 
6  Permission is hereby granted, free of charge, to any person obtaining a copy
7  of this software and associated documentation files (the "Software"), to deal
8  in the Software without restriction, including without limitation the rights
9  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  copies of the Software, and to permit persons to whom the Software is
11  furnished to do so, subject to the following conditions:
12 
13  The above copyright notice and this permission notice shall be included in all
14  copies or substantial portions of the Software.
15 
16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  SOFTWARE.
23 
24  */
25 
26 #include "symbolic4.h"
27 
28 char* keyword_strings[] = {
29  "=",
30  "+",
31  "-",
32  "*",
33  "/",
34  "^",
35  "abs",
36  "ln",
37  "log",
38  "arcsin",
39  "arccos",
40  "arctan",
41  "sin",
42  "cos",
43  "tan",
44  "simplify",
45  "simp",
46  "solve",
47  "Factors",
48  "Fac",
49  "Value",
50  "Val",
51  "Derivative",
52  "Deriv",
53  "Integral",
54  "Int",
55  "Area",
56  "StationaryPoints",
57  "StatPts",
58  "InflectionPoints",
59  "InflPts",
60  "Tangent",
61  "Tang",
62  "VectorMagnitude",
63  "VMag",
64  "VectorNormalized",
65  "VNormed",
66  "Normal",
67  "Norm",
68  "VectorAngle",
69  "VAng",
70  "Angle",
71  "Ang",
72  "VectorDotProduct",
73  "VDotP",
74  "VectorCrossProduct",
75  "VCrossP",
76  "VectorTripleProduct",
77  "VTripleP",
78  "approximate",
79  "approx",
80  "List",
81  "Ls",
82  "Vector",
83  "Vec",
84  ",",
85  "(",
86  ")",
87  "parse",
88  NULL
89 };
90 
98  EXPI_ABS,
99  EXPI_LN,
100  EXPI_LOG,
101  EXPI_ARCSIN,
102  EXPI_ARCCOS,
103  EXPI_ARCTAN,
104  EXPI_SIN,
105  EXPI_COS,
106  EXPI_TAN,
109  EXPI_SOLVE,
110  EXPI_FACTORS,
111  EXPI_FACTORS,
112  EXPI_VALUE,
113  EXPI_VALUE,
118  EXPI_AREA,
123  EXPI_TANGENT,
124  EXPI_TANGENT,
125  EXPI_V_MAG,
126  EXPI_V_MAG,
129  EXPI_NORMAL,
130  EXPI_NORMAL,
131  EXPI_V_ANGLE,
132  EXPI_V_ANGLE,
133  EXPI_ANGLE,
134  EXPI_ANGLE,
143  EXPI_LIST,
144  EXPI_LIST,
145  EXPI_LIST,
146  EXPI_LIST,
147  EXPI_COMMA,
150  EXPI_PARSE,
151  EXPI_NULL
152 };
153 
154 void expression_to_infix(char* buffer, const expression* souce);
155 void expression_to_tikz(char* buffer, const expression* source);
156 
157 /**
158 
159  @brief Allocates and initializes a new expression with the arguments
160  provided
161 
162  @details
163  This function returns a new expression which is initialized with
164  the arguments provided and in sign = 1. This function is especially
165  useful when being nested to build up more complex expressions in one
166  line. Children are not copied.
167 
168  @param[in] type The expression type.
169  @param[in] identifier The expression identifier.
170  @param[in] child_count The number of children. It must match the
171  actual number of children provided.
172  @param[in] ... The child expressions. They may be calls to
173  @c new_expression().
174 
175  @return
176  - The initialized expression.
177 
178  @see
179  - new_literal()
180  - new_symbol()
181 
182  */
183 expression* new_expression(expression_type type, expression_identifier identifier, uint8_t child_count, ...) {
184 
185  uint8_t i;
186  va_list arguments;
187  expression* result = smart_alloc(1, sizeof(expression));
188 
189  result->type = type;
190  result->identifier = identifier;
191  result->sign = 1;
192 
193  va_start(arguments, child_count);
194 
195  for (i = 0; i < child_count; i++) {
196  append_child(result, va_arg(arguments, expression*));
197  }
198 
199  va_end(arguments);
200 
201  return result;
202 
203 }
204 
205 /**
206 
207  @brief Allocates and initializes a new literal expression
208 
209  @details
210  This function returns a new literal which is initialized with the
211  arguments provided. The result is automatically reduced.
212 
213  @param[in] sign (either 1 or -1)
214  @param[in] numerator The numeric numerator.
215  @param[in] denominator The numeric denominator.
216 
217  @return
218  - The initialized literal.
219 
220  @see
221  - new_expression()
222  - new_symbol()
223 
224  */
225 expression* new_literal(int8_t sign, uintmax_t numerator, uintmax_t denominator) {
227  result->sign = sign;
228  result->value.numeric.numerator = numerator;
229  result->value.numeric.denominator = denominator;
230  return result;
231 }
232 
233 /**
234 
235  @brief Allocates and initializes a new symbol/variable expression
236 
237  @details
238  This function returns a new literal which is initialized with the
239  argument provided.
240 
241  @param[in] identifier (either @c EXPI_SYMBOL or @c EXPI_VARIABLE)
242  @param[in] value The symbolic value.
243 
244  @return
245  - The initialized symbol.
246 
247  @see
248  - new_expression()
249  - new_literal()
250 
251  */
252 expression* new_symbol(expression_identifier identifier, const char* value) {
253  expression* result = new_expression(EXPT_VALUE, (identifier == EXPI_VARIABLE) ? EXPI_VARIABLE : EXPI_SYMBOL, 0);
254  strcpy(result->value.symbolic, value);
255  return result;
256 }
257 
259 
261  new_literal(1, period, 1),
262  new_symbol(EXPI_SYMBOL, "n"),
263  new_symbol(EXPI_SYMBOL, "pi"));
264 
265  return result;
266 
267 }
268 
269 /**
270 
271  @brief Returns a deep copy of an expression
272 
273  @details
274  This function recursively (post-order traversal) copies an expression
275  and all its children. The copied expression is returned.
276 
277  @note
278  - Null-children are not included in the copy.
279 
280  @param[in] source The expression to copy.
281 
282  @return
283  - Pointer to the copy.
284 
285  */
287 
288  uint8_t i;
290 
291  if (source == NULL) return NULL;
292 
293  for (i = 0; i < source->child_count; i++) {
294  if (source->children[i] == NULL) continue;
295  append_child(result, copy_expression(source->children[i]));
296  }
297 
298  result->parent = source->parent;
299  result->type = source->type;
300  result->identifier = source->identifier;
301  result->child_count = source->child_count;
302  result->sign = source->sign;
303  result->value = source->value;
304 
305  return result;
306 
307 }
308 
310  free_expression(a, true);
311  *a = *b;
312  smart_free(b);
313 }
314 
315 void free_expression(expression* source, bool persistent) {
316 
317  uint8_t i;
318 
319  if (source == NULL) {
320  return;
321  }
322 
323  for (i = 0; i < source->child_count; i++) {
324  if (source->children[i] == NULL) continue;
325  free_expression(source->children[i], false);
326  source->children[i] = NULL;
327  }
328 
329  source->child_count = 0;
330 
331  if (!persistent) {
332  smart_free(source);
333  source = NULL;
334  }
335 
336 }
337 
338 void free_expressions(uint8_t expression_count, ...) {
339 
340  uint8_t i;
341  va_list arguments;
342 
343  va_start(arguments, expression_count);
344 
345  for (i = 0; i < expression_count; i++) {
346  free_expression(va_arg(arguments, expression*), false);
347  }
348 
349  va_end(arguments);
350 
351 }
352 
354 
355  uint16_t i;
356  expression* temp;
357 
358  for (i = 0; allocated_pointers[i] != source && i < ALLOCATED_POINTERS_LENGTH; i++);
359  allocated_pointers[i] = NULL;
360 
361  smart_alloc_is_recording = false;
362  temp = copy_expression(source);
363  smart_free_all();
364 
366  *source = *copy_expression(temp);
367  free_expression(temp, false);
368 
369 }
370 
371 /**
372 
373  @brief Appends a child to an expression
374 
375  @details
376  When @c DEBUG_MODE is set to 0 (production mode),
377  the children pointer is resized to hold the new child.
378 
379  @param[in,out] parent The destination parent.
380  @param[in] child The child to be appended.
381 
382  */
383 void append_child(expression* parent, expression* child) {
384  uint16_t i;
385 #ifdef DEBUG_MODE
386  parent->children[parent->child_count] = child;
387  parent->child_count++;
388 #else
389  for (i = 0; allocated_pointers[i] != parent->children && i < ALLOCATED_POINTERS_LENGTH; i++);
390  allocated_pointers[i] = NULL;
391  parent->children = smart_realloc(parent->children, parent->child_count + 1, sizeof(expression));
392  parent->children[parent->child_count] = child;
393  parent->child_count++;
394 #endif
395 }
396 
397 void remove_child_at_index(expression* source, uint8_t index) {
398  free_expression(source->children[index], false);
399  source->children[index] = NULL;
400  remove_null_children(source);
401 }
402 
404 
405  uint8_t i;
406  expression* result = new_expression(source->type, source->identifier, 0);
407 
408  for (i = 0; i < source->child_count; i++) {
409  if (source->children[i] == NULL) continue;
410  append_child(result, copy_expression(source->children[i]));
411  }
412 
413  replace_expression(source, result);
414 
415 }
416 
418  if (source->identifier != EXPI_LIST) {
420  source));
421  }
422 }
423 
424 void merge_nested_lists(expression* source, bool recursive) {
425 
426  uint8_t i, j;
427  expression* result;
428 
429  for (i = 0; i < source->child_count && recursive; i++) {
430  merge_nested_lists(source->children[i], true);
431  }
432 
433  if (source->identifier != EXPI_LIST) return;
434 
436 
437  for (i = 0; i < source->child_count; i++) {
438  if (source->children[i]->identifier == EXPI_LIST) {
439  for (j = 0; j < source->children[i]->child_count; j++) {
440  append_child(result, copy_expression(source->children[i]->children[j]));
441  }
442  } else {
443  append_child(result, copy_expression(source->children[i]));
444  }
445  }
446 
447  if (result->child_count == 1) {
448  replace_expression(result, copy_expression(result->children[0]));
449  }
450 
451  replace_expression(source, result);
452 
453 }
454 
455 void set_parents(expression* source) {
456 
457  uint8_t i;
458 
459  for (i = 0; i < source->child_count; i++) {
460  if (source->children[i] == NULL) continue;
461  source->children[i]->parent = source;
462  set_parents(source->children[i]);
463  }
464 
465 }
466 
467 bool expressions_are_identical(const expression* a, expression* b, bool persistent) {
468 
469  uint8_t i;
470 
471  if (a == NULL || b == NULL) {
472  return false;
473  }
474 
475  if (a->identifier != b->identifier) {
476  if (!persistent) free_expression(b, false);
477  return false;
478  }
479 
480  if (a->sign != b->sign) {
481  if (!persistent) free_expression(b, false);
482  return false;
483  }
484 
486  if (!persistent) free_expression(b, false);
487  return false;
488  }
489 
490  if (a->identifier == EXPI_SYMBOL && strcmp(a->value.symbolic, b->value.symbolic) != 0) {
491  if (!persistent) free_expression(b, false);
492  return false;
493  }
494 
495  if (a->type == EXPT_OPERATION || a->type == EXPT_FUNCTION || a->type == EXPT_STRUCTURE) {
496 
497  if (a->child_count != b->child_count) {
498  if (!persistent) free_expression(b, false);
499  return false;
500  }
501 
502  for (i = 0; i < a->child_count; i++) {
503 
504  if (a->children[i] == NULL && b->children[i] == NULL) continue;
505 
506  if (a->children[i] == NULL || b->children[i] == NULL) {
507  if (!persistent) free_expression(b, false);
508  return false;
509  }
510 
511  if (expressions_are_identical(a->children[i], b->children[i], true) == false) {
512  if (!persistent) free_expression(b, false);
513  return false;
514  }
515 
516  }
517 
518  }
519 
520  if (!persistent) free_expression(b, false);
521 
522  return true;
523 
524 }
525 
526 bool expressions_are_equivalent(const expression* a, expression* b, bool persistent) {
527 
529  copy_expression(a),
530  copy_expression(b));
531 
532  simplify(temp, true);
533  temp->sign = 1;
534 
535  if (!persistent) free_expression(b, false);
536 
537  if (expressions_are_identical(temp, new_literal(1, 0, 1), false)) {
538  free_expression(temp, false);
539  return true;
540  } else {
541  free_expression(temp, false);
542  return false;
543  }
544 
545 }
546 
547 bool expression_is_greater_than(const expression* a, expression* b, bool persistent) {
548 
549  expression* temp_a = copy_expression(a);
550  expression* temp_b = copy_expression(b);
551 
553  temp_a,
554  temp_b);
555 
556  simplify(test, true);
557 
558  if (!persistent) free_expression(b, false);
559 
560  if (test->identifier == EXPI_LITERAL && test->sign == 1 && literal_to_double(test) != 0) {
561  free_expression(test, false);
562  return true;
563  } else {
564  free_expression(test, false);
565  return false;
566  }
567 
568 }
569 
570 bool expression_is_smaller_than(const expression* a, expression* b, bool persistent) {
571 
572  expression* temp_a = copy_expression(a);
573  expression* temp_b = copy_expression(b);
574 
576  temp_a,
577  temp_b);
578 
579  simplify(test, true);
580 
581  if (!persistent) free_expression(b, false);
582 
583  if (test->identifier == EXPI_LITERAL && test->sign == -1) {
584  free_expression(test, false);
585  return true;
586  } else {
587  free_expression(test, false);
588  return false;
589  }
590 
591 }
592 
593 bool expression_is_constant(const expression* source) {
594 
595  uint8_t i;
596 
597  for (i = 0; i < source->child_count; i++) {
598  if (!expression_is_constant(source->children[i])) {
599  return false;
600  }
601  }
602 
603  if (source->identifier == EXPI_SYMBOL && !symbol_is_constant(source)) {
604  return false;
605  } else {
606  return true;
607  }
608 
609 }
610 
611 bool symbol_is_constant(const expression* source) {
612  if (source->identifier == EXPI_SYMBOL &&
613  (strcmp(source->value.symbolic, "pi") == 0 ||
614  strcmp(source->value.symbolic, "e") == 0 ||
615  strcmp(source->value.symbolic, "i") == 0)) {
616  return true;
617  } else {
618  return false;
619  }
620 }
621 
623 
624  uint8_t i;
625 
626  for (i = 0; i < source->child_count && source->identifier == EXPI_MULTIPLICATION; i++) {
627  if (source->children[i]->identifier == EXPI_EXPONENTATION && source->children[i]->children[1]->sign == -1) {
628  return i;
629  }
630  }
631 
632  return -1;
633 
634 }
635 
637 
638  if (source->identifier == EXPI_EXPONENTATION) {
639  if (source->children[1]->sign == -1) return true;
640  }
641 
642  return false;
643 
644 }
645 
646 bool expression_is_numerical(const expression* source) {
647 
648  uint8_t i;
649 
650  for (i = 0; i < source->child_count; i++) {
651  if (!expression_is_numerical(source->children[i])) {
652  return false;
653  }
654  }
655 
656  if (source->identifier == EXPI_SYMBOL) {
657  return false;
658  } else {
659  return true;
660  }
661 
662 }
663 
664 uint8_t count_occurrences(const expression* haystack, expression* needle, bool persistent) {
665 
666  uint8_t i;
667  uint8_t count = 0;
668 
669  if (expressions_are_identical(haystack, needle, true)) {
670 
671  if (!persistent) free_expression(needle, false);
672  return 1;
673 
674  } else {
675 
676  for (i = 0; i < haystack->child_count; i++) {
677  if (haystack->children[i] == NULL) continue;
678  count += count_occurrences(haystack->children[i], needle, true);
679  }
680 
681  if (!persistent) free_expression(needle, false);
682  return count;
683 
684  }
685 
686 }
687 
688 void replace_occurences(expression* source, const expression* child, const expression* replacement) {
689 
690  uint8_t i;
691 
692  for (i = 0; i < source->child_count; i++) {
693  if (source->children[i] == NULL) continue;
694  replace_occurences(source->children[i], child, replacement);
695  }
696 
697  if (expressions_are_identical(source, copy_expression(child), false)) {
698  replace_expression(source, copy_expression(replacement));
699  }
700 
701 }
702 
704 
705  uint8_t i;
706 
707  for (i = 0; i < source->child_count; i++) {
708  if (source->children[i] == NULL ||
709  (source->children[i]->type == EXPT_STRUCTURE && source->children[i]->child_count == 0)) {
710  source->children[i] = new_literal(1, 0, 1);
711  } else {
712  replace_null_with_zero(source->children[i]);
713  }
714  }
715 
716 }
717 
719 
720  expression* temp;
721 
722  if (a == NULL || b == NULL) return RETS_ERROR;
723 
724  temp = a;
725  b = a;
726  b = temp;
727 
728  return RETS_SUCCESS;
729 
730 }
731 
732 uint8_t get_symbol_order_score(const expression* source) {
733 
734  char* occurance;
735 
736  if (source->identifier != EXPI_SYMBOL || strlen(source->value.symbolic) != 1) return 100;
737 
738  if ((occurance = strstr(default_priorities, source->value.symbolic))) {
739  return (uint8_t) (occurance - default_priorities);
740  } else {
741  return 100;
742  }
743 
744 }
745 
746 double get_order_score(const expression* source) {
747 
748  uint8_t i;
749  double score;
750 
751  if (source->identifier == EXPI_LITERAL) {
752  score = 1;
753  } else if (source->identifier == EXPI_SYMBOL) {
754  score = 2 + get_symbol_order_score(source);
755  } else if (source->identifier == EXPI_ADDITION || source->identifier == EXPI_MULTIPLICATION) {
756  score = 1000;
757  for (i = 0; i < source->child_count; i++) score += get_order_score(source->children[i]) / 2;
758  } else if (source->identifier == EXPI_EXPONENTATION) {
759  score = 20000 + get_order_score(source->children[0]) / 2;
760  } else {
761  score = 30000;
762  for (i = 0; i < source->child_count; i++) score += get_order_score(source->children[i]) / 2;
763  }
764 
765  return score;
766 
767 }
768 
769 void order_children(expression* source) {
770 
771  uint8_t i;
772  expression** expressions;
773  double* scores;
774  uint8_t min_index;
775  double min_score;
776  expression* result;
777 
778  if (source->identifier != EXPI_ADDITION && source->identifier != EXPI_MULTIPLICATION) return;
779 
780  expressions = smart_alloc(source->child_count, sizeof(expression));
781  scores = smart_alloc(source->child_count, sizeof(double));
782 
783  result = new_expression(source->type, source->identifier, 0);
784 
785  remove_null_children(source);
786 
787  for (i = 0; i < source->child_count; i++) {
788  expressions[i] = source->children[i];
789  scores[i] = get_order_score(source->children[i]);
790  }
791 
792  while (result->child_count != source->child_count) {
793 
794  min_index = 0;
795  min_score = uintmax_max_value();
796 
797  for (i = 0; i < source->child_count; i++) {
798  if (scores[i] < min_score && scores[i] != 0) {
799  min_index = i;
800  min_score = scores[i];
801  }
802  }
803 
804  append_child(result, copy_expression(expressions[min_index]));
805  scores[min_index] = 0;
806 
807  }
808 
809  smart_free(expressions);
810  smart_free(scores);
811  replace_expression(source, result);
812 
813 }
814 
815 void collect_symbols(expression* symbols, const expression* source) {
816 
817  uint8_t i;
818 
819  for (i = 0; i < source->child_count; i++) {
820  if (source->children[i] == NULL) continue;
821  collect_symbols(symbols, source->children[i]);
822  }
823 
824  if (source->identifier == EXPI_SYMBOL || source->identifier == EXPI_VARIABLE) {
825  append_child(symbols, copy_expression(source));
826  }
827 
828 }
829 
830 expression* guess_symbol(const expression* source, const char* custom_priorities, uint8_t rank) {
831 
832  uint8_t i, j;
834  expression* symbol;
835 
836  collect_symbols(symbols, source);
837 
838  for (i = 0; custom_priorities[i] != '\0'; i++) {
839  for (j = 0; j < symbols->child_count; j++) {
840  if (strlen(symbols->children[j]->value.symbolic) == 1 && symbols->children[j]->value.symbolic[0] == custom_priorities[i]) {
841  if (rank == 0) {
842  symbol = copy_expression(symbols->children[j]);
843  free_expression(symbols, false);
844  return symbol;
845  } else {
846  rank--;
847  }
848  }
849  }
850  }
851 
852  for (i = 0; default_priorities[i] != '\0'; i++) {
853  for (j = 0; j < symbols->child_count; j++) {
854  if (strlen(symbols->children[j]->value.symbolic) == 1 && symbols->children[j]->value.symbolic[0] == default_priorities[i]) {
855  if (rank == 0) {
856  symbol = copy_expression(symbols->children[j]);
857  free_expression(symbols, false);
858  return symbol;
859  } else {
860  rank--;
861  }
862  }
863  }
864  }
865 
866  if (symbols->child_count != 0) {
867  symbol = copy_expression(symbols->children[0]);
868  free_expression(symbols, false);
869  return symbol;
870  }
871 
872  free_expression(symbols, false);
873 
874  return NULL;
875 
876 }
877 
879 
880  expression* symbol;
881 
882  if (source->identifier == EXPI_POLYNOMIAL_SPARSE) {
883  return copy_expression(source->children[0]->children[2]);
884  } else if (source->identifier == EXPI_POLYNOMIAL_DENSE) {
885  return copy_expression(source->children[0]);
886  } else {
887  symbol = guess_symbol(source, "", 0);
888  if (symbol) {
889  return symbol;
890  } else {
891  return new_symbol(EXPI_SYMBOL, "x");
892  }
893  }
894 }
895 
896 expression* double_to_literal(double source) {
897 
898  char* buffer = smart_alloc(10, sizeof(char));
899  expression* result;
900 
901  dtoa(buffer, 10, source);
902  string_to_literal(&result, buffer);
903 
904  return result;
905 
906 }
907 
908 double literal_to_double(expression* source) {
909  return source->sign * ((double) source->value.numeric.numerator) / ((double) source->value.numeric.denominator);
910 }
911 
913 
914  uint8_t i;
915  char* buffer;
916 
917  for (i = 0; i < source->child_count; i++) {
918  if (source->children[i] == 0) continue;
920  }
921 
922  if (source->identifier == EXPI_LITERAL) {
923  buffer = smart_alloc(10, sizeof(char));
924  dtoa(buffer, 10, literal_to_double(source));
925  replace_expression(source, new_symbol(EXPI_SYMBOL, buffer));
926  }
927 
928 }
929 
930 /**
931 
932  @brief Returns the keyword string corresponding to the identifier
933 
934  @details
935  The @c keyword_identifiers array is searched for the first occurrence
936  of the given identifier. When found, the string from
937  @c keyword_strings with the same index is returned. If
938  @c use_abbrevations is set to true, the abbrevation (the next string,
939  if existent) is returned.
940 
941  @param[in] identifier The expression identifier.
942 
943  @return
944  - The string corresponding to the identifier.
945 
946  @see
947  - get_expression_identifier()
948 
949  */
951 
952  uint8_t i;
953 
954  for (i = 0; keyword_identifiers[i] != EXPI_NULL; i++) {
955  if (keyword_identifiers[i] == identifier) {
956  if (use_abbrevations && keyword_identifiers[i + 1] == identifier) {
957  return keyword_strings[i + 1];
958  } else {
959  return keyword_strings[i];
960  }
961  }
962  }
963 
964  return "NULL";
965 
966 }
967 
968 /**
969 
970  @brief Returns the identifier corresponding to the keyword string
971 
972  @details
973  The @c keyword_strings array is searched for the first occurrence
974  of the given string. When found, the identifier from
975  @c keyword_identifiers with the same index is returned. This function
976  is case insensitive and handles abbrevations.
977 
978  @param[in] string The keyword string.
979 
980  @return
981  - The identifier corresponding to the string.
982 
983  @see
984  - get_expression_string()
985 
986  */
988 
989  uint8_t i;
990  char* lowercase_string = string_to_lower(string);
991  char* lowercase_keyword;
992 
993  for (i = 0; keyword_strings[i] != NULL; i++) {
994  lowercase_keyword = string_to_lower(keyword_strings[i]);
995  if (strcmp(string, lowercase_keyword) == 0) {
996  smart_free(lowercase_string);
997  smart_free(lowercase_keyword);
998  return keyword_identifiers[i];
999  }
1000  smart_free(lowercase_keyword);
1001  }
1002 
1003  smart_free(lowercase_string);
1004 
1005  return EXPI_NULL;
1006 
1007 }
1008 
1009 /**
1010 
1011  @brief Serializes an expression into a specified format
1012 
1013  @details
1014  This function calls @c expression_to_infix() or
1015  @c expression_to_tkiz(), depending on the specified format. It
1016  automatically converts all polynomials to expressions and sets
1017  parents. No further simplification is applied. The result can be
1018  tweaked by changing the bools @c use_abbrevations and @c use_spaces,
1019  defined in symbolic4.c.
1020 
1021  @param[in,out] buffer The buffer where the resulting string shall be
1022  written into.
1023  @param[in] source The expression to be serialized.
1024  @param[in] format The serialization format.
1025 
1026  @see
1027  - expression_to_infix()
1028  - expression_to_tkiz()
1029 
1030  */
1031 void expression_to_string(char* buffer, const expression* source, expression_to_string_format format) {
1032 
1033  expression* temp_source = copy_expression(source);
1034 
1036  set_parents(temp_source);
1037 
1038  switch (format) {
1039  case ETSF_INFIX: expression_to_infix(buffer, temp_source); break;
1040  case ETSF_TIKZ: strcat(buffer, "\\begin{tikzpicture}"); expression_to_tikz(buffer, temp_source); strcat(buffer, ";\\end{tikzpicture}"); break;
1041  default: expression_to_infix(buffer, temp_source); break;
1042  }
1043 
1044  free_expression(temp_source, false);
1045 
1046 }
1047 
1048 void expression_to_infix(char* buffer, const expression* source) {
1049 
1050  uint8_t i;
1051  char temp_buffer[30];
1052  expression* temp_source = copy_expression(source);
1053 
1054  if (temp_source->identifier == EXPI_LITERAL) {
1055  if (temp_source->value.numeric.denominator == 1) {
1056  if (temp_source->sign == -1) strcat(buffer, "(-");
1057  itoa(temp_buffer, temp_source->value.numeric.numerator);
1058  strcat(buffer, temp_buffer);
1059  if (temp_source->sign == -1) strcat(buffer, ")");
1060  } else {
1061  strcat(buffer, "(");
1062  if (temp_source->sign == -1) strcat(buffer, "-");
1063  itoa(temp_buffer, temp_source->value.numeric.numerator);
1064  strcat(buffer, temp_buffer);
1065  strcat(buffer, (use_spaces) ? " / " : "/");
1066  itoa(temp_buffer, temp_source->value.numeric.denominator);
1067  strcat(buffer, temp_buffer);
1068  strcat(buffer, ")");
1069  }
1070  }
1071 
1072  if (temp_source->identifier == EXPI_SYMBOL || temp_source->identifier == EXPI_VARIABLE) {
1073  strcat(buffer, temp_source->value.symbolic);
1074  }
1075 
1076  if (temp_source->type == EXPT_OPERATION) {
1077  if (temp_source->parent == NULL || (temp_source->identifier >= temp_source->parent->identifier || temp_source->parent->type != EXPT_OPERATION)) {
1078  for (i = 0; i < temp_source->child_count; i++) {
1079  expression_to_infix(buffer, temp_source->children[i]);
1080  if (use_spaces && i != temp_source->child_count - 1) strcat(buffer, " ");
1081  if (i != temp_source->child_count - 1) strcat(buffer, get_expression_string(temp_source->identifier));
1082  if (use_spaces && i != temp_source->child_count - 1) strcat(buffer, " ");
1083  }
1084  } else {
1085  strcat(buffer, "(");
1086  for (i = 0; i < temp_source->child_count; i++) {
1087  expression_to_infix(buffer, temp_source->children[i]);
1088  if (use_spaces && i != temp_source->child_count - 1) strcat(buffer, " ");
1089  if (i != temp_source->child_count - 1) strcat(buffer, get_expression_string(temp_source->identifier));
1090  if (use_spaces && i != temp_source->child_count - 1) strcat(buffer, " ");
1091  }
1092  strcat(buffer, ")");
1093  }
1094  }
1095 
1096  if (temp_source->type == EXPT_FUNCTION || temp_source->type == EXPT_STRUCTURE) {
1097  strcat(buffer, get_expression_string(temp_source->identifier));
1098  strcat(buffer, "(");
1099  for (i = 0; i < temp_source->child_count; i++) {
1100  expression_to_infix(buffer, temp_source->children[i]);
1101  if (i != temp_source->child_count - 1) strcat(buffer, (use_spaces) ? ", " : ",");
1102  }
1103  strcat(buffer, ")");
1104  }
1105 
1106  free_expression(temp_source, false);
1107 
1108 }
1109 
1110 /**
1111 
1112  @code
1113  \tikzset{
1114  treenode/.style = {align = center, inner sep = 1mm},
1115  operator_node/.style = {treenode, circle, draw = black},
1116  function_node/.style = {treenode, rectangle, draw = black},
1117  node_nil/.style = {treenode, circle, black}
1118  }
1119  @endcode
1120 
1121  */
1122 void expression_to_tikz(char* buffer, const expression* source) {
1123 
1124  uint8_t i;
1125  char temp_buffer[30];
1126  expression* temp_source = copy_expression(source);
1127 
1128  if (temp_source->identifier == EXPI_LITERAL) {
1129  strcat(buffer, "child{node{$");
1130  if (temp_source->sign == -1) strcat(buffer, "- ");
1131  if (temp_source->value.numeric.denominator == 1) {
1132  itoa(temp_buffer, temp_source->value.numeric.numerator);
1133  strcat(buffer, temp_buffer);
1134  } else {
1135  strcat(buffer, "\\frac{");
1136  itoa(temp_buffer, temp_source->value.numeric.numerator);
1137  strcat(buffer, temp_buffer);
1138  strcat(buffer, "}{");
1139  itoa(temp_buffer, temp_source->value.numeric.denominator);
1140  strcat(buffer, temp_buffer);
1141  strcat(buffer, "}");
1142  }
1143  strcat(buffer, "$}}");
1144  }
1145 
1146  if (temp_source->identifier == EXPI_SYMBOL || temp_source->identifier == EXPI_VARIABLE) {
1147  strcat(buffer, "child{node{$");
1148  if (temp_source->sign == -1) strcat(buffer, "- ");
1149  strcat(buffer, (strcmp(temp_source->value.symbolic, "pi") == 0) ? "\\pi" : temp_source->value.symbolic);
1150  strcat(buffer, "$}}");
1151  }
1152 
1153  if (temp_source->type == EXPT_OPERATION) {
1154  strcat(buffer, (temp_source->parent) ? "child{node[operator_node]{$" : "\\node[operator_node]{$");
1155  if (temp_source->sign == -1) strcat(buffer, "- ");
1156  strcat(buffer, (temp_source->identifier == EXPI_EXPONENTATION) ? "\\wedge" : get_expression_string(temp_source->identifier));
1157  strcat(buffer, "$}");
1158  for (i = 0; i < temp_source->child_count; i++) expression_to_tikz(buffer, temp_source->children[i]);
1159  if (temp_source->parent) strcat(buffer, "}");
1160  }
1161 
1162  if (temp_source->type == EXPT_FUNCTION || temp_source->type == EXPT_STRUCTURE) {
1163  strcat(buffer, (temp_source->parent) ? "child{node[function_node]{" : "\\node[function_node]{");
1164  if (temp_source->sign == -1) strcat(buffer, "- ");
1165  strcat(buffer, get_expression_string(temp_source->identifier));
1166  strcat(buffer, "}");
1167  for (i = 0; i < temp_source->child_count; i++) expression_to_tikz(buffer, temp_source->children[i]);
1168  if (temp_source->parent) strcat(buffer, "}");
1169  }
1170 
1171  free_expression(temp_source, false);
1172 
1173 }
1174 
1175 #ifdef DEBUG_MODE
1176 void print_expression(const expression* source) {
1177  char buffer[500];
1178  memset(buffer, '\0', 500);
1179  expression_to_string(buffer, source, ETSF_INFIX);
1180  printf("%s\n", buffer);
1181 }
1182 #endif
merge_nested_lists
void merge_nested_lists(expression *source, bool recursive)
Definition: expression.c:424
EXPI_SOLVE
Definition: expression.h:66
EXPI_LIST
Definition: expression.h:90
EXPI_NULL
Definition: expression.h:42
EXPT_FUNCTION
Definition: expression.h:35
smart_free_all
void smart_free_all(void)
Frees all pointers.
Definition: foundation.c:133
numeric_value::denominator
uintmax_t denominator
Definition: expression.h:109
get_symbol_order_score
uint8_t get_symbol_order_score(const expression *source)
Definition: expression.c:732
expression_contains_division
int8_t expression_contains_division(const expression *source)
Definition: expression.c:622
expression_is_numerical
bool expression_is_numerical(const expression *source)
Definition: expression.c:646
symbolic4.h
EXPI_LEFT_PARENTHESIS
Definition: expression.h:95
EXPI_LN
Definition: expression.h:56
embed_in_list_if_necessary
void embed_in_list_if_necessary(expression *source)
Definition: expression.c:417
EXPI_EXPONENTATION
Definition: expression.h:53
EXPI_ARCTAN
Definition: expression.h:63
expression::symbolic
char symbolic[10]
Definition: expression.h:128
expression::type
expression_type type
Definition: expression.h:114
EXPI_POLYNOMIAL_DENSE
Definition: expression.h:89
EXPI_SYMBOL
Definition: expression.h:45
expression_identifier
expression_identifier
Definition: expression.h:40
expression_is_smaller_than
bool expression_is_smaller_than(const expression *a, expression *b, bool persistent)
Definition: expression.c:570
EXPI_ABS
Definition: expression.h:55
default_priorities
char * default_priorities
Definition: symbolic4.c:30
replace_expression
void replace_expression(expression *a, expression *b)
Definition: expression.c:309
EXPI_COMMA
Definition: expression.h:94
expression
Definition: expression.h:112
expression::identifier
expression_identifier identifier
Definition: expression.h:115
literal_to_double_symbol
void literal_to_double_symbol(expression *source)
Definition: expression.c:912
EXPI_COS
Definition: expression.h:59
get_expression_identifier
expression_identifier get_expression_identifier(const char *string)
Returns the identifier corresponding to the keyword string.
Definition: expression.c:987
literal_to_double
double literal_to_double(expression *source)
Definition: expression.c:908
replace_occurences
void replace_occurences(expression *source, const expression *child, const expression *replacement)
Definition: expression.c:688
EXPT_STRUCTURE
Definition: expression.h:36
EXPI_V_TRIPLE_PRODUCT
Definition: expression.h:84
EXPI_RIGHT_PARENTHESIS
Definition: expression.h:96
EXPI_V_MAG
Definition: expression.h:79
ETSF_INFIX
Definition: expression.h:103
smart_free
void smart_free(void *pointer)
Frees a pointer.
Definition: foundation.c:112
expression::sign
int8_t sign
Definition: expression.h:117
EXPI_V_NORMALIZED
Definition: expression.h:80
EXPI_LOG
Definition: expression.h:57
EXPT_VALUE
Definition: expression.h:33
EXPI_STATIONARY_POINTS
Definition: expression.h:73
EXPI_TANGENT
Definition: expression.h:75
collect_symbols
void collect_symbols(expression *symbols, const expression *source)
Definition: expression.c:815
new_symbol
expression * new_symbol(expression_identifier identifier, const char *value)
Allocates and initializes a new symbol/variable expression.
Definition: expression.c:252
get_symbol
expression * get_symbol(const expression *source)
Definition: expression.c:878
EXPI_ARCSIN
Definition: expression.h:61
expression::value
union expression::@0 value
expression_to_tikz
void expression_to_tikz(char *buffer, const expression *source)
Definition: expression.c:1122
double_to_literal
expression * double_to_literal(double source)
Definition: expression.c:896
EXPI_V_CROSS_PRODUCT
Definition: expression.h:83
dtoa
void dtoa(char *buffer, uint8_t length, double source)
Definition: foundation.c:233
expression_to_infix
void expression_to_infix(char *buffer, const expression *souce)
Definition: expression.c:1048
EXPI_NORMAL
Definition: expression.h:76
RETS_SUCCESS
Definition: foundation.h:67
use_spaces
bool use_spaces
Determines if spaces should be used in the result string (such as "x + y * z" instead of "x+y*z")
Definition: symbolic4.c:29
order_children
void order_children(expression *source)
Definition: expression.c:769
expressions_are_identical
bool expressions_are_identical(const expression *a, expression *b, bool persistent)
Definition: expression.c:467
ETSF_TIKZ
Definition: expression.h:104
uintmax_max_value
double uintmax_max_value(void)
Definition: foundation.c:188
EXPI_DERIVATIVE
Definition: expression.h:70
itoa
void itoa(char *buffer, uintmax_t source)
Definition: foundation.c:216
RETS_ERROR
Definition: foundation.h:66
remove_child_at_index
void remove_child_at_index(expression *source, uint8_t index)
Definition: expression.c:397
string_to_lower
char * string_to_lower(const char *string)
Converts a string to lowercase.
Definition: foundation.c:206
free_expression
void free_expression(expression *source, bool persistent)
Definition: expression.c:315
EXPI_PARSE
Definition: expression.h:97
string_to_literal
uint8_t string_to_literal(expression **result, const char *source)
Definition: parser.c:201
EXPI_MULTIPLICATION
Definition: expression.h:51
EXPI_SIN
Definition: expression.h:58
EXPI_INFLECTION_POINTS
Definition: expression.h:74
EXPI_FACTORS
Definition: expression.h:67
swap_expressions
uint8_t swap_expressions(expression *a, expression *b)
Definition: expression.c:718
EXPI_POLYNOMIAL_SPARSE
Definition: expression.h:88
free_expressions
void free_expressions(uint8_t expression_count,...)
Definition: expression.c:338
count_occurrences
uint8_t count_occurrences(const expression *haystack, expression *needle, bool persistent)
Definition: expression.c:664
EXPT_OPERATION
Definition: expression.h:34
get_order_score
double get_order_score(const expression *source)
Definition: expression.c:746
expression::parent
struct expression * parent
Definition: expression.h:118
expression_type
expression_type
Definition: expression.h:31
smart_alloc_is_recording
bool smart_alloc_is_recording
Definition: foundation.c:30
expression::numeric
numeric_value numeric
Definition: expression.h:129
expression_to_string
void expression_to_string(char *buffer, const expression *source, expression_to_string_format format)
Serializes an expression into a specified format.
Definition: expression.c:1031
EXPI_AREA
Definition: expression.h:72
ALLOCATED_POINTERS_LENGTH
#define ALLOCATED_POINTERS_LENGTH
Definition: symbolic4.h:30
expression_is_constant
bool expression_is_constant(const expression *source)
Definition: expression.c:593
copy_expression
expression * copy_expression(const expression *source)
Returns a deep copy of an expression.
Definition: expression.c:286
free_all_except
void free_all_except(expression *source)
Definition: expression.c:353
EXPI_SUBTRACTION
Definition: expression.h:50
simplify
uint8_t simplify(expression *source, bool recursive)
Definition: simplify.c:1117
any_expression_to_expression_recursive
void any_expression_to_expression_recursive(expression *source)
Definition: polynomial.c:44
get_expression_string
const char * get_expression_string(expression_identifier identifier)
Returns the keyword string corresponding to the identifier.
Definition: expression.c:950
append_child
void append_child(expression *parent, expression *child)
Appends a child to an expression.
Definition: expression.c:383
keyword_strings
char * keyword_strings[]
Definition: expression.c:28
new_expression
expression * new_expression(expression_type type, expression_identifier identifier, uint8_t child_count,...)
Allocates and initializes a new expression with the arguments provided.
Definition: expression.c:183
expression_is_greater_than
bool expression_is_greater_than(const expression *a, expression *b, bool persistent)
Definition: expression.c:547
EXPI_EQUATION
Definition: expression.h:48
EXPI_TAN
Definition: expression.h:60
EXPI_ARCCOS
Definition: expression.h:62
remove_null_children
void remove_null_children(expression *source)
Definition: expression.c:403
EXPI_APPROXIMATE
Definition: expression.h:86
EXPI_VARIABLE
Definition: expression.h:46
replace_null_with_zero
void replace_null_with_zero(expression *source)
Definition: expression.c:703
EXPI_V_DOT_PRODUCT
Definition: expression.h:82
keyword_identifiers
expression_identifier keyword_identifiers[]
Definition: expression.c:91
guess_symbol
expression * guess_symbol(const expression *source, const char *custom_priorities, uint8_t rank)
Definition: expression.c:830
new_literal
expression * new_literal(int8_t sign, uintmax_t numerator, uintmax_t denominator)
Allocates and initializes a new literal expression.
Definition: expression.c:225
EXPI_ADDITION
Definition: expression.h:49
EXPI_INTEGRAL
Definition: expression.h:71
EXPI_VALUE
Definition: expression.h:68
smart_realloc
void * smart_realloc(void *source, uint8_t length, size_t size)
Resizes a pointer.
Definition: foundation.c:86
expression_to_string_format
expression_to_string_format
Definition: expression.h:101
allocated_pointers
void ** allocated_pointers
Definition: foundation.c:29
new_trigonometic_periodicity
expression * new_trigonometic_periodicity(uint8_t period)
Definition: expression.c:258
EXPT_NULL
Definition: expression.h:32
expressions_are_equivalent
bool expressions_are_equivalent(const expression *a, expression *b, bool persistent)
Definition: expression.c:526
EXPI_V_ANGLE
Definition: expression.h:81
expression::child_count
uint8_t child_count
Definition: expression.h:119
expression::children
struct expression ** children
Definition: expression.h:124
EXPI_ANGLE
Definition: expression.h:77
EXPI_SIMPLIFY
Definition: expression.h:65
expression_is_reziprocal
bool expression_is_reziprocal(const expression *source)
Definition: expression.c:636
numeric_value::numerator
uintmax_t numerator
Definition: expression.h:108
use_abbrevations
bool use_abbrevations
Determines if abbrevations should be used in the result string (such as "Deriv" instead of "Derivativ...
Definition: symbolic4.c:28
symbol_is_constant
bool symbol_is_constant(const expression *source)
Definition: expression.c:611
set_parents
void set_parents(expression *source)
Definition: expression.c:455
EXPI_DIVISION
Definition: expression.h:52
smart_alloc
void * smart_alloc(uint8_t length, size_t size)
Allocates and keeps track of memory.
Definition: foundation.c:59
EXPI_LITERAL
Definition: expression.h:44