symbolic4
derivative.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 uint8_t addition_derivative(expression** result, const expression* source, const expression* variable);
29 uint8_t multiplication_derivative(expression** result, const expression* source, const expression* variable);
30 uint8_t exponentation_derivative(expression** result, const expression* source, const expression* variable);
31 uint8_t ln_derivative(expression** result, const expression* source, const expression* variable);
32 uint8_t log_derivative(expression** result, const expression* source, const expression* variable);
33 uint8_t trigonometric_derivative(expression** result, const expression* source, const expression* variable);
34 
35 uint8_t addition_derivative(expression** result, const expression* source, const expression* variable) {
36 
37  uint8_t i;
38  expression* temp_result;
39 
41 
42  for (i = 0; i < source->child_count; i++) {
43  if (source->children[i] == NULL) continue;
44  ERROR_CHECK(derivative(&temp_result, copy_expression(source->children[i]), copy_expression(variable), false));
45  append_child(*result, temp_result);
46  }
47 
48  return RETS_SUCCESS;
49 
50 }
51 
52 uint8_t multiplication_derivative(expression** result, const expression* source, const expression* variable) {
53 
54  uint8_t i, j;
55  expression* temp_result;
56 
58 
59  for (i = 0; i < source->child_count; i++) {
60  if (source->children[i] == NULL) continue;
62  for (j = 0; j < source->child_count; j++) {
63  if (source->children[i] == NULL) continue;
64  if (i == j) {
65  ERROR_CHECK(derivative(&temp_result, copy_expression(source->children[j]), copy_expression(variable), false));
66  append_child((*result)->children[(*result)->child_count - 1], temp_result);
67  } else {
68  append_child((*result)->children[(*result)->child_count - 1], copy_expression(source->children[j]));
69  }
70  }
71  }
72 
73  return RETS_SUCCESS;
74 
75 }
76 
77 uint8_t exponentation_derivative(expression** result, const expression* source, const expression* variable) {
78 
79  expression* temp_result;
80 
81  if (count_occurrences(source->children[1], copy_expression(variable), false) > 0) {
82 
83  ERROR_CHECK(derivative(&temp_result, copy_expression(source->children[1]), copy_expression(variable), false));
84 
86  append_child(*result, copy_expression(source));
87 
88  if (count_occurrences(source->children[0], copy_expression(variable), false) > 0) {
92  temp_result),
94  copy_expression(source->children[1]),
95  copy_expression(source->children[0]))));
96  } else if (expressions_are_identical(source->children[0], new_symbol(EXPI_SYMBOL, "e"), false)) {
97  } else {
99  }
100 
101  ERROR_CHECK(derivative(&temp_result, copy_expression(source->children[1]), copy_expression(variable), false));
102  append_child(*result, temp_result);
103 
104  } else {
105 
106  ERROR_CHECK(derivative(&temp_result, copy_expression(source->children[0]), copy_expression(variable), false));
107 
109  copy_expression(source->children[1]),
111  copy_expression(source->children[0]),
113  copy_expression(source->children[1]),
114  new_literal(-1, 1, 1))),
115  temp_result);
116 
117  }
118 
119 
120  return RETS_SUCCESS;
121 
122 }
123 
124 uint8_t ln_derivative(expression** result, const expression* source, const expression* variable) {
125 
126  expression* temp_result;
127 
128  ERROR_CHECK(derivative(&temp_result, copy_expression(source->children[0]), copy_expression(variable), false));
130  temp_result,
131  copy_expression(source->children[0]));
132 
133  return RETS_SUCCESS;
134 
135 }
136 
137 uint8_t log_derivative(expression** result, const expression* source, const expression* variable) {
138 
139  expression* temp_result;
140  expression* base = (source->child_count == 1) ? new_literal(1, 10, 1) : copy_expression(source->children[1]);
141 
142  ERROR_CHECK(derivative(&temp_result, copy_expression(source->children[0]), copy_expression(variable), false));
144  temp_result,
147  copy_expression(source->children[0])));
148 
149  return RETS_SUCCESS;
150 
151 }
152 
153 uint8_t trigonometric_derivative(expression** result, const expression* source, const expression* variable) {
154 
155  expression* temp_result;
156 
158 
159  switch (source->identifier) {
160  case EXPI_SIN:
162  break;
163  case EXPI_COS:
164  append_child(*result, new_literal(-1, 1, 1));
166  break;
167  case EXPI_TAN:
170  new_literal(-1, 2, 1)));
171  break;
172  case EXPI_ARCSIN:
175  new_literal(1, 1, 1),
177  copy_expression(source->children[0]),
178  new_literal(1, 2, 1))),
179  new_literal(-1, 1, 2)));
180  break;
181  case EXPI_ARCCOS:
182  append_child(*result, new_literal(-1, 1, 1));
185  new_literal(1, 1, 1),
187  copy_expression(source->children[0]),
188  new_literal(1, 2, 1))),
189  new_literal(-1, 1, 2)));
190  break;
191  case EXPI_ARCTAN:
195  copy_expression(source->children[0]),
196  new_literal(1, 2, 1)),
197  new_literal(1, 1, 1))));
198  break;
199  default: break;
200  }
201 
202  ERROR_CHECK(derivative(&temp_result, copy_expression(source->children[0]), copy_expression(variable), true));
203  append_child(*result, temp_result);
204 
205  return RETS_SUCCESS;
206 
207 }
208 
209 uint8_t derivative(expression** result, expression* source, expression* variable, bool persistent) {
210 
211  if (variable == NULL) {
212  variable = guess_symbol(source, "", 0);
213  if (variable == NULL) {
214  *result = new_literal(1, 0, 1);
215  return RETS_SUCCESS;
216  }
217  }
218 
220  ERROR_CHECK(simplify(source, true));
221 
222  if (count_occurrences(source, copy_expression(variable), false) == 0) {
223  *result = new_literal(1, 0, 1);
224  if (!persistent) {
225  free_expression(source, false);
226  free_expression(variable, false);
227  }
228  return RETS_SUCCESS;
229  }
230 
231  switch (source->identifier) {
232  case EXPI_SYMBOL: *result = (expressions_are_identical(source, copy_expression(variable), false)) ? new_literal(1, 1, 1) : new_literal(1, 0, 1); break;
233  case EXPI_ADDITION: addition_derivative(result, source, variable); break;
234  case EXPI_MULTIPLICATION: multiplication_derivative(result, source, variable); break;
235  case EXPI_EXPONENTATION: exponentation_derivative(result, source, variable); break;
236  case EXPI_LN: ln_derivative(result, source, variable); break;
237  case EXPI_LOG: log_derivative(result, source, variable); break;
238  case EXPI_SIN:
239  case EXPI_COS:
240  case EXPI_TAN:
241  case EXPI_ARCSIN:
242  case EXPI_ARCCOS:
243  case EXPI_ARCTAN: trigonometric_derivative(result, source, variable); break;
246  }
247 
248  ERROR_CHECK(simplify(*result, true));
249 
250  if (!persistent) {
251  free_expression(source, false);
252  free_expression(variable, false);
253  }
254 
255  return RETS_SUCCESS;
256 
257 }
258 
259 uint8_t stationary_points(expression* source, expression* variable) {
260 
261  uint8_t i;
262  expression* first_derivative;
263  expression* second_derivative;
264  expression* first_derivatives_roots;
265  expression* second_derivative_value;
266  expression* function_value;
267  expression* result;
268 
269  if (variable == NULL) {
270  variable = guess_symbol(source, "", 0);
271  }
272 
273  ERROR_CHECK(derivative(&first_derivative, source, variable, true));
274  ERROR_CHECK(derivative(&second_derivative, first_derivative, variable, true));
275 
276  first_derivatives_roots = new_expression(EXPT_OPERATION, EXPI_EQUATION, 2,
277  copy_expression(first_derivative),
278  new_literal(1, 0, 1));
279 
280  switch (solve(first_derivatives_roots, variable)) {
281  case RETS_UNCHANGED: return RETS_UNCHANGED;
282  case RETS_ERROR: return RETS_ERROR;
283  }
284 
285  embed_in_list_if_necessary(first_derivatives_roots);
286 
288 
289  for (i = 0; i < first_derivatives_roots->child_count; i++) {
290 
291  function_value = copy_expression(source);
292  replace_occurences(function_value, variable, first_derivatives_roots->children[i]->children[1]);
293 
294  second_derivative_value = copy_expression(second_derivative);
295  replace_occurences(second_derivative_value, variable, first_derivatives_roots->children[i]->children[1]);
296 
297  if (expressions_are_equivalent(second_derivative_value, new_literal(1, 0, 1), false)) {
299  copy_expression(first_derivatives_roots->children[i]->children[1]),
300  copy_expression(function_value),
301  new_literal(1, 0, 1)));
302  } else if (expression_is_greater_than(second_derivative_value, new_literal(1, 0, 1), false)) {
304  copy_expression(first_derivatives_roots->children[i]->children[1]),
305  copy_expression(function_value),
306  new_literal(-1, 1, 1)));
307  } else if (expression_is_smaller_than(second_derivative_value, new_literal(1, 0, 1), false)) {
309  copy_expression(first_derivatives_roots->children[i]->children[1]),
310  copy_expression(function_value),
311  new_literal(1, 1, 1)));
312  } else {
314  copy_expression(first_derivatives_roots->children[i]->children[1]),
315  copy_expression(function_value)));
316  }
317 
318  }
319 
320 
321  simplify(result, true);
322 
323  replace_expression(source, result);
324 
325  return RETS_SUCCESS;
326 
327 }
328 
329 uint8_t function_tangent(expression** result, expression* source, expression* variable, expression* x_value, bool persistent) {
330 
331  expression* y_value;
332  expression* slope;
333 
334  ERROR_CHECK(derivative(result, source, variable, true));
335 
336  y_value = copy_expression(source);
337  replace_occurences(y_value, variable, x_value);
338 
339  slope = copy_expression(*result);
340  replace_occurences(slope, variable, x_value);
341 
344  copy_expression(slope),
345  copy_expression(variable)),
347  copy_expression(y_value),
349  copy_expression(x_value),
350  copy_expression(slope))));
351 
352  free_expression(y_value, false);
353  free_expression(slope, false);
354 
355  if (!persistent) {
356  free_expression(source, false);
357  free_expression(variable, false);
358  free_expression(x_value, false);
359  }
360 
361  ERROR_CHECK(simplify(*result, true));
362 
363  return RETS_SUCCESS;
364 
365 }
366 
367 uint8_t function_normal(expression** result, expression* source, expression* variable, expression* x_value, bool persistent) {
368 
369  expression* y_value;
370  expression* slope;
371 
372  ERROR_CHECK(derivative(result, source, variable, true));
373 
374  y_value = copy_expression(source);
375  replace_occurences(y_value, variable, x_value);
376 
378  new_literal(-1, 1, 1),
379  copy_expression(*result));
380  replace_occurences(slope, variable, x_value);
381 
384  copy_expression(slope),
385  copy_expression(variable)),
387  copy_expression(y_value),
389  copy_expression(x_value),
390  copy_expression(slope))));
391 
392  free_expression(y_value, false);
393  free_expression(slope, false);
394 
395  if (!persistent) {
396  free_expression(source, false);
397  free_expression(variable, false);
398  free_expression(x_value, false);
399  }
400 
401  ERROR_CHECK(simplify(*result, true));
402 
403  return RETS_SUCCESS;
404 
405 }
406 
408 
409  uint8_t i;
411  copy_expression(g),
412  copy_expression(h));
413  expression* variable = guess_symbol(equation, "", 0);
414  expression* g_derivative;
415  expression* h_derivative;
416  expression* g_slope;
417  expression* h_slope;
418 
419  solve(equation, NULL);
420  embed_in_list_if_necessary(equation);
421 
422  for (i = 0; i < equation->child_count; i++) {
423  if (equation->children[i]->children[0]->identifier != EXPI_SYMBOL) {
425  copy_expression(g),
426  copy_expression(h));
427  return RETS_UNCHANGED;
428  }
429  }
430 
431  *result = new_expression(EXPT_STRUCTURE, EXPI_LIST, 0);
432  derivative(&g_derivative, g, variable, true);
433  derivative(&h_derivative, h, variable, true);
434 
435  for (i = 0; i < equation->child_count; i++) {
436 
437  g_slope = copy_expression(g_derivative);
438  replace_occurences(g_slope, variable, copy_expression(equation->children[i]->children[1]));
439  simplify(g_slope, true);
440 
441  h_slope = copy_expression(h_derivative);
442  replace_occurences(h_slope, variable, copy_expression(equation->children[i]->children[1]));
443  simplify(h_slope, true);
444 
449  copy_expression(g_slope),
450  copy_expression(h_slope)),
452  new_literal(1, 1, 1),
454  copy_expression(g_slope),
455  copy_expression(h_slope)))))));
456 
457  free_expression(g_slope, false);
458  free_expression(h_slope, false);
459 
460 
461  }
462 
463  simplify(*result, true);
464 
465  merge_nested_lists(*result, false);
466 
467  return RETS_SUCCESS;
468 
469 }
merge_nested_lists
void merge_nested_lists(expression *source, bool recursive)
Definition: expression.c:424
EXPI_LIST
Definition: expression.h:90
EXPT_FUNCTION
Definition: expression.h:35
symbolic4.h
stationary_points
uint8_t stationary_points(expression *source, expression *variable)
Definition: derivative.c:259
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
EXPI_SYMBOL
Definition: expression.h:45
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
derivative
uint8_t derivative(expression **result, expression *source, expression *variable, bool persistent)
Definition: derivative.c:209
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
replace_occurences
void replace_occurences(expression *source, const expression *child, const expression *replacement)
Definition: expression.c:688
EXPT_STRUCTURE
Definition: expression.h:36
function_intersection_angle
uint8_t function_intersection_angle(expression **result, expression *g, expression *h)
Definition: derivative.c:407
ERRD_SYNTAX
Definition: foundation.h:36
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
solve
uint8_t solve(expression *source, expression *variable)
Definition: solve.c:337
RETS_UNCHANGED
Definition: foundation.h:69
RETS_SUCCESS
Definition: foundation.h:67
expressions_are_identical
bool expressions_are_identical(const expression *a, expression *b, bool persistent)
Definition: expression.c:467
RETS_ERROR
Definition: foundation.h:66
trigonometric_derivative
uint8_t trigonometric_derivative(expression **result, const expression *source, const expression *variable)
Definition: derivative.c:153
ln_derivative
uint8_t ln_derivative(expression **result, const expression *source, const expression *variable)
Definition: derivative.c:124
free_expression
void free_expression(expression *source, bool persistent)
Definition: expression.c:315
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
function_tangent
uint8_t function_tangent(expression **result, expression *source, expression *variable, expression *x_value, bool persistent)
Definition: derivative.c:329
count_occurrences
uint8_t count_occurrences(const expression *haystack, expression *needle, bool persistent)
Definition: expression.c:664
EXPT_OPERATION
Definition: expression.h:34
addition_derivative
uint8_t addition_derivative(expression **result, const expression *source, const expression *variable)
Definition: derivative.c:35
multiplication_derivative
uint8_t multiplication_derivative(expression **result, const expression *source, const expression *variable)
Definition: derivative.c:52
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
function_normal
uint8_t function_normal(expression **result, expression *source, expression *variable, expression *x_value, bool persistent)
Definition: derivative.c:367
simplify
uint8_t simplify(expression *source, bool recursive)
Definition: simplify.c:1117
ERRI_NON_DIFFERENTIABLE
Definition: foundation.h:61
any_expression_to_expression_recursive
void any_expression_to_expression_recursive(expression *source)
Definition: polynomial.c:44
ERRD_MATH
Definition: foundation.h:37
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
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
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
log_derivative
uint8_t log_derivative(expression **result, const expression *source, const expression *variable)
Definition: derivative.c:137
ERRI_UNEXPECTED_EXPRESSION
Definition: foundation.h:53
expressions_are_equivalent
bool expressions_are_equivalent(const expression *a, expression *b, bool persistent)
Definition: expression.c:526
exponentation_derivative
uint8_t exponentation_derivative(expression **result, const expression *source, const expression *variable)
Definition: derivative.c:77
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_DIVISION
Definition: expression.h:52