symbolic4
solve.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 bool isolation_changed = false;
29 
30 uint8_t attract_variables(expression* source, expression* variable) {
31 
32  if (count_occurrences(source->children[1], variable, true) > 0) {
35  copy_expression(source->children[0]),
36  copy_expression(source->children[1])),
37  new_literal(1, 0, 1)));
38  }
39 
40  ERROR_CHECK(simplify(source, true));
41 
42  return RETS_SUCCESS;
43 
44 }
45 
46 void subtract_rhs(expression* source) {
47 
48  expression* result;
49 
50  if (source->identifier != EXPI_EQUATION) {
51  return;
52  }
53 
55  copy_expression(source->children[0]),
56  copy_expression(source->children[1]));
57 
58  simplify(result, true);
59 
60 }
61 
62 uint8_t isolate_variable_in_addition(expression* source, expression* variable) {
63 
64  uint8_t i;
66 
67  for (i = 0; i < source->children[0]->child_count; i++) {
68  if (count_occurrences(source->children[0]->children[i], variable, true) == 0) {
69  append_child(temp, source->children[0]->children[i]);
70  source->children[0]->children[i] = NULL;
71  isolation_changed = true;
72  }
73  }
74 
76  copy_expression(source->children[1]),
77  temp));
78 
79  ERROR_CHECK(simplify(source, true));
80 
81  return RETS_SUCCESS;
82 
83 }
84 
86 
87  uint8_t i;
89 
90  for (i = 0; i < source->children[0]->child_count; i++) {
91  if (count_occurrences(source->children[0]->children[i], variable, true) == 0) {
92  append_child(temp, source->children[0]->children[i]);
93  source->children[0]->children[i] = NULL;
94  isolation_changed = true;
95  }
96  }
97 
99  copy_expression(source->children[1]),
100  temp));
101 
102  ERROR_CHECK(simplify(source, true));
103 
104  return RETS_SUCCESS;
105 
106 }
107 
109 
110  expression* result;
111 
112  if (count_occurrences(source->children[0]->children[0], variable, true) == 0) {
113 
114  /* variable is in exponent -> logarithms */
115 
117  copy_expression(source->children[0]->children[1]),
119  copy_expression(source->children[1]),
120  copy_expression(source->children[0]->children[0]))));
121 
122  } else if (count_occurrences(source->children[0]->children[1], variable, true) == 0) {
123 
124  /* variable is in base -> roots */
125 
127  copy_expression(source->children[1]),
129  new_literal(1, 1, 1),
130  copy_expression(source->children[0]->children[1])));
131 
132  ERROR_CHECK(simplify(result, true));
133 
134 
135 
136  if (source->children[0]->children[1]->identifier == EXPI_LITERAL && source->children[0]->children[1]->value.numeric.numerator % 2 == 0 && source->children[0]->children[1]->value.numeric.denominator == 1 &&
137  !expressions_are_identical(result, new_literal(1, 0, 1), false)) {
140  copy_expression(source->children[0]->children[0]),
142  new_literal(-1, 1, 1),
143  copy_expression(result))),
145  copy_expression(source->children[0]->children[0]),
146  copy_expression(result))));
147  } else {
149  copy_expression(source->children[0]->children[0]),
150  copy_expression(result)));
151  }
152 
153  free_expression(result, true);
154 
155  }
156 
157  ERROR_CHECK(simplify(source, true));
158 
159  isolation_changed = true;
160 
161  return RETS_SUCCESS;
162 
163 }
164 
166 
168  copy_expression(source->children[0]->children[0]),
170  new_symbol(EXPI_SYMBOL, "e"),
171  copy_expression(source->children[1]))));
172 
173  ERROR_CHECK(simplify(source, true));
174 
175  isolation_changed = true;
176 
177  return RETS_SUCCESS;
178 
179 }
180 
182 
183  expression* base;
184 
185  if (source->children[0]->child_count == 1) {
186  base = new_literal(1, 10, 1);
187  } else {
188  base = copy_expression(source->children[0]->children[1]);
189  }
190 
192  copy_expression(source->children[0]->children[0]),
194  base,
195  copy_expression(source->children[1]))));
196 
197  ERROR_CHECK(simplify(source, true));
198 
199  isolation_changed = true;
200 
201  return RETS_SUCCESS;
202 
203 }
204 
206 
207  uint8_t i;
208  expression* right_side;
209 
210  switch (source->children[0]->identifier) {
211 
212  case EXPI_SIN:
213  right_side = new_expression(EXPT_STRUCTURE, EXPI_LIST, 2,
218  new_symbol(EXPI_SYMBOL, "pi"),
222  break;
223 
224  case EXPI_COS:
225  right_side = new_expression(EXPT_STRUCTURE, EXPI_LIST, 2,
231  new_literal(1, 2, 1),
232  new_symbol(EXPI_SYMBOL, "pi")),
236  break;
237 
238  case EXPI_TAN:
242  break;
243 
244  case EXPI_ARCSIN:
245  right_side = new_expression(EXPT_FUNCTION, EXPI_SIN, 1, copy_expression(source->children[1]));
246  break;
247 
248  case EXPI_ARCCOS:
249  right_side = new_expression(EXPT_FUNCTION, EXPI_COS, 1, copy_expression(source->children[1]));
250  break;
251 
252  case EXPI_ARCTAN:
253  right_side = new_expression(EXPT_FUNCTION, EXPI_TAN, 1, copy_expression(source->children[1]));
254  break;
255 
256  default: return set_error(ERRD_SYSTEM, ERRI_UNEXPECTED_EXPRESSION, "");
257 
258  }
259 
260  simplify(right_side, true);
261 
262  if (right_side->identifier == EXPI_LIST) {
263  for (i = 0; i < right_side->child_count; i++) {
265  copy_expression(source->children[0]->children[0]),
266  copy_expression(right_side->children[i])));
267  }
268  replace_expression(source, right_side);
269  } else {
271  copy_expression(source->children[0]->children[0]),
272  right_side));
273  }
274 
275  isolation_changed = true;
276 
277  return RETS_SUCCESS;
278 
279 }
280 
281 uint8_t isolate_variable(expression* source, expression* variable) {
282 
283  uint8_t i;
284  isolation_changed = false;
285 
286  if (source->identifier == EXPI_LIST) {
287 
288  for (i = 0; i < source->child_count; i++) {
289  ERROR_CHECK(isolate_variable(source->children[i], variable));
290  }
291 
292  return RETS_SUCCESS;
293 
294  }
295 
296  switch (source->children[0]->identifier) {
297  case EXPI_ADDITION: ERROR_CHECK(isolate_variable_in_addition(source, variable)); break;
299  case EXPI_EXPONENTATION: ERROR_CHECK(isolate_variable_in_exponentation(source, variable)); break;
300  case EXPI_LN: ERROR_CHECK(isolate_variable_in_ln(source)); break;
301  case EXPI_LOG: ERROR_CHECK(isolate_variable_in_log(source)); break;
302  case EXPI_SIN:
303  case EXPI_COS:
304  case EXPI_TAN:
305  case EXPI_ARCSIN:
306  case EXPI_ARCCOS:
308  default: return RETS_UNCHANGED;
309  }
310 
311  if (isolation_changed) ERROR_CHECK(isolate_variable(source, variable));
312 
313  return RETS_SUCCESS;
314 
315 }
316 
317 uint8_t handle_right_side_is_zero(expression* source, expression* variable) {
318 
319  uint8_t i;
320 
321  if (source->children[0]->identifier == EXPI_MULTIPLICATION) {
322  for (i = 0; i < source->children[0]->child_count; i++) {
323  if (source->children[0]->children[i]->identifier == EXPI_EXPONENTATION && expression_is_constant(source->children[0]->children[i]->children[1]) &&
324  source->children[0]->children[i]->children[1]->sign == -1) {
325  free_expression(source->children[0]->children[i], false);
326  source->children[0]->children[i] = NULL;
327  }
328  }
329  simplify(source->children[0], true);
330  return RETS_CHANGED;
331  }
332 
333  return RETS_CHANGED;
334 
335 }
336 
337 uint8_t solve(expression* source, expression* variable) {
338 
339  if (variable == NULL) {
340  variable = guess_symbol(source, "", 0);
341  if (variable == NULL) return RETS_SUCCESS;
342  } else if (count_occurrences(source, variable, true) == 0) {
343  return set_error(ERRD_SYNTAX, ERRI_ARGUMENTS, "");
344  }
345 
346  ERROR_CHECK(attract_variables(source, variable));
347 
348  if (expressions_are_identical(source->children[1], new_literal(1, 0, 1), false)) {
349  switch (handle_right_side_is_zero(source, variable)) {
350  case RETS_CHANGED: break;
351  case RETS_SUCCESS: return RETS_SUCCESS;
352  case RETS_ERROR: return RETS_ERROR;
353  }
354  }
355 
356  if (count_occurrences(source, variable, true) == 1) {
357  ERROR_CHECK(isolate_variable(source, variable));
358  } else {
359  ERROR_CHECK(polysolve(source, variable) == RETS_UNCHANGED);
360  }
361 
362  return RETS_SUCCESS;
363 
364 }
365 
366 
ERRI_ARGUMENTS
Definition: foundation.h:58
EXPI_LIST
Definition: expression.h:90
EXPT_FUNCTION
Definition: expression.h:35
numeric_value::denominator
uintmax_t denominator
Definition: expression.h:109
symbolic4.h
EXPI_LN
Definition: expression.h:56
EXPI_EXPONENTATION
Definition: expression.h:53
isolate_variable_in_ln
uint8_t isolate_variable_in_ln(expression *source)
Definition: solve.c:165
EXPI_ARCTAN
Definition: expression.h:63
EXPI_SYMBOL
Definition: expression.h:45
isolate_variable_in_exponentation
uint8_t isolate_variable_in_exponentation(expression *source, expression *variable)
Definition: solve.c:108
replace_expression
void replace_expression(expression *a, expression *b)
Definition: expression.c:309
expression
Definition: expression.h:112
expression::identifier
expression_identifier identifier
Definition: expression.h:115
EXPI_COS
Definition: expression.h:59
EXPT_STRUCTURE
Definition: expression.h:36
isolation_changed
bool isolation_changed
Definition: solve.c:28
ERRD_SYNTAX
Definition: foundation.h:36
expression::sign
int8_t sign
Definition: expression.h:117
subtract_rhs
void subtract_rhs(expression *source)
Definition: solve.c:46
ERROR_CHECK
#define ERROR_CHECK(F)
Check if the return status of a function is RETS_ERROR. If so, return RETS_ERROR.
Definition: foundation.h:31
EXPI_LOG
Definition: expression.h:57
new_symbol
expression * new_symbol(expression_identifier identifier, const char *value)
Allocates and initializes a new symbol/variable expression.
Definition: expression.c:252
EXPI_ARCSIN
Definition: expression.h:61
expression::value
union expression::@0 value
isolate_variable_in_log
uint8_t isolate_variable_in_log(expression *source)
Definition: solve.c:181
solve
uint8_t solve(expression *source, expression *variable)
Definition: solve.c:337
RETS_UNCHANGED
Definition: foundation.h:69
RETS_SUCCESS
Definition: foundation.h:67
isolate_variable_in_multiplication
uint8_t isolate_variable_in_multiplication(expression *source, expression *variable)
Definition: solve.c:85
isolate_variable_in_addition
uint8_t isolate_variable_in_addition(expression *source, expression *variable)
Definition: solve.c:62
expressions_are_identical
bool expressions_are_identical(const expression *a, expression *b, bool persistent)
Definition: expression.c:467
RETS_CHANGED
Definition: foundation.h:68
isolate_variable_in_trigonometric_function
uint8_t isolate_variable_in_trigonometric_function(expression *source)
Definition: solve.c:205
RETS_ERROR
Definition: foundation.h:66
free_expression
void free_expression(expression *source, bool persistent)
Definition: expression.c:315
handle_right_side_is_zero
uint8_t handle_right_side_is_zero(expression *source, expression *variable)
Definition: solve.c:317
EXPI_MULTIPLICATION
Definition: expression.h:51
EXPI_SIN
Definition: expression.h:58
set_error
uint8_t set_error(error_domain domain, error_identifier identifier, const char *body)
Sets current_error to the arguments provided.
Definition: foundation.c:152
ERRD_SYSTEM
Definition: foundation.h:35
count_occurrences
uint8_t count_occurrences(const expression *haystack, expression *needle, bool persistent)
Definition: expression.c:664
EXPT_OPERATION
Definition: expression.h:34
expression::numeric
numeric_value numeric
Definition: expression.h:129
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
EXPI_SUBTRACTION
Definition: expression.h:50
simplify
uint8_t simplify(expression *source, bool recursive)
Definition: simplify.c:1117
append_child
void append_child(expression *parent, expression *child)
Appends a child to an expression.
Definition: expression.c:383
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
EXPI_EQUATION
Definition: expression.h:48
EXPI_TAN
Definition: expression.h:60
EXPI_ARCCOS
Definition: expression.h:62
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
ERRI_UNEXPECTED_EXPRESSION
Definition: foundation.h:53
new_trigonometic_periodicity
expression * new_trigonometic_periodicity(uint8_t period)
Definition: expression.c:258
expression::child_count
uint8_t child_count
Definition: expression.h:119
expression::children
struct expression ** children
Definition: expression.h:124
isolate_variable
uint8_t isolate_variable(expression *source, expression *variable)
Definition: solve.c:281
polysolve
return_status polysolve(expression *source, expression *variable)
Definition: polynomial.c:440
numeric_value::numerator
uintmax_t numerator
Definition: expression.h:108
attract_variables
uint8_t attract_variables(expression *source, expression *variable)
Definition: solve.c:30
EXPI_DIVISION
Definition: expression.h:52
EXPI_LITERAL
Definition: expression.h:44