Skip to content

Commit

Permalink
Add partial derivatives and tests (#209)
Browse files Browse the repository at this point in the history
* Add partial derivatives and tests

* Update README.md

* Update README for deriv module

* Reformat deriv_test.v

* Remove unnecessary lines

* Shorten README

* reformat deriv.v

* Update Readme

* Update deriv/deriv.v

Co-authored-by: Ulises Jeremias <ulisescf.24@gmail.com>

* Update deriv_test.v

* Update deriv.v

* run `v fmt -w deriv/deriv.v`

---------

Co-authored-by: Ulises Jeremias <ulisescf.24@gmail.com>
Co-authored-by: Delyan Angelov <delian66@gmail.com>
  • Loading branch information
3 people authored Jul 27, 2024
1 parent b671cae commit 05590e5
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 0 deletions.
12 changes: 12 additions & 0 deletions deriv/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,18 @@ for values greater than `x`. 📉

This function is equivalent to calling `deriv.forward` with a negative step-size.

### `partial`

```v ignore
pub fn partial(f fn ([]f64) f64, x []f64, variable int, h f64) (f64, f64)
```

This function computes the partial derivative of the function `f` with respect to
a specified variable at point `x` using step-size `h`. It returns the derivative
in `result` and an error estimate in `abserr`. The function `f` should take an array
of coordinates and return a single value. This method provides both the derivative
and its error estimate.

## References and Further Reading

This work is a spiritual descendent of the Differentiation module in [GSL](https://github.com/ampl/gsl). 📖
Expand Down
30 changes: 30 additions & 0 deletions deriv/deriv.v
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module deriv

import vsl.func
import vsl.errors
import vsl.internal.prec
import math

Expand Down Expand Up @@ -113,3 +114,32 @@ pub fn forward(f func.Fn, x f64, h f64) (f64, f64) {
pub fn backward(f func.Fn, x f64, h f64) (f64, f64) {
return forward(f, x, -h)
}

/**
* partial is a function that computes the partial derivative of a multivariable function with respect to a specified variable.
*
* @param f The multivariable function for which the partial derivative is to be computed.
* @param x The point at which the partial derivative is to be computed, represented as an array of coordinates.
* @param variable The index of the variable with respect to which the partial derivative is to be computed.
* @param h The step size to be used in the central difference method.
*
* @return A tuple containing the value of the partial derivative and the estimated error.
*/
pub fn partial(f fn ([]f64) f64, x []f64, variable int, h f64) (f64, f64) {
if variable < 0 || variable >= x.len {
errors.vsl_panic('Invalid variable index', .efailed)
}

// Define a helper function that converts the multivariate function
// to a univariate function for the specified variable
partial_helper := func.Fn{
f: fn [f, x, variable] (t f64, _ []f64) f64 {
mut x_new := x.clone()
x_new[variable] = t
return f(x_new)
}
}

// Use the central difference method to compute the partial derivative
return central(partial_helper, x[variable], h)
}
24 changes: 24 additions & 0 deletions deriv/deriv_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ fn df6(x f64, _ []f64) f64 {
return -1.0 / (x * x)
}

fn f_multi(x []f64) f64 {
return x[0] * x[0] + x[1] * x[1] // f(x,y) = x^2 + y^2
}

fn df_multi_dx(x []f64) f64 {
return 2 * x[0] // ∂f/∂x = 2x
}

fn df_multi_dy(x []f64) f64 {
return 2 * x[1] // ∂f/∂y = 2y
}

fn test_deriv() {
f1_ := func.Fn.new(f: f1)
df1_ := func.Fn.new(f: df1)
Expand Down Expand Up @@ -100,6 +112,18 @@ fn test_deriv() {
assert deriv_test('central', f6_, df6_, 10.0)
assert deriv_test('forward', f6_, df6_, 10.0)
assert deriv_test('backward', f6_, df6_, 10.0)

// Partial derivative test
x := [2.0, 3.0]
h := 1e-5

// Partial derivative with respect to x
dx, _ := partial(f_multi, x, 0, h)
assert float64.tolerance(dx, df_multi_dx(x), 1e-5)

// Partial derivative with respect to y
dy, _ := partial(f_multi, x, 1, h)
assert float64.tolerance(dy, df_multi_dy(x), 1e-5)
}

fn deriv_test(deriv_method string, f func.Fn, df func.Fn, x f64) bool {
Expand Down

0 comments on commit 05590e5

Please sign in to comment.