Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add partial derivatives and tests #209

Merged
merged 12 commits into from
Jul 27, 2024
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
Expand Up @@ -113,3 +113,33 @@ 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)
}

pub fn partial(f fn ([]f64) f64, x []f64, variable int, h f64) (f64, f64) {
/**
* 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.
*/
ulises-jeremias marked this conversation as resolved.
Show resolved Hide resolved

if variable < 0 || variable >= x.len {
panic('Invalid variable index')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use this function instead of panic https://vlang.github.io/vsl/errors.html#vsl_panic

}

// 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
spytheman marked this conversation as resolved.
Show resolved Hide resolved
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