@@ -85,21 +85,21 @@ impl<F: Float> Clone for GpInnerParams<F> {
85
85
/// * `regr(x)` a vector of polynomial basis functions
86
86
/// * `sigma^2` is the process variance
87
87
/// * `corr(x, x')` is a correlation function which depends on `distance(x, x')`
88
- /// and a set of unknown parameters `thetas` to be determined.
88
+ /// and a set of unknown parameters `thetas` to be determined.
89
89
///
90
90
/// # Implementation
91
91
///
92
92
/// * Based on [ndarray](https://github.com/rust-ndarray/ndarray)
93
- /// and [linfa](https://github.com/rust-ml/linfa) and strive to follow [linfa guidelines](https://github.com/rust-ml/linfa/blob/master/CONTRIBUTE.md)
93
+ /// and [linfa](https://github.com/rust-ml/linfa) and strive to follow [linfa guidelines](https://github.com/rust-ml/linfa/blob/master/CONTRIBUTE.md)
94
94
/// * GP mean model can be constant, linear or quadratic
95
95
/// * GP correlation model can be build the following kernels: squared exponential, absolute exponential, matern 3/2, matern 5/2
96
- /// cf. [SMT Kriging](https://smt.readthedocs.io/en/latest/_src_docs/surrogate_models/krg.html)
96
+ /// cf. [SMT Kriging](https://smt.readthedocs.io/en/latest/_src_docs/surrogate_models/krg.html)
97
97
/// * For high dimensional problems, the classic GP algorithm does not perform well as
98
- /// it depends on the inversion of a correlation (n, n) matrix which is an O(n3) operation.
99
- /// To work around this problem the library implements dimension reduction using
100
- /// Partial Least Squares method upon Kriging method also known as KPLS algorithm (see Reference)
98
+ /// it depends on the inversion of a correlation (n, n) matrix which is an O(n3) operation.
99
+ /// To work around this problem the library implements dimension reduction using
100
+ /// Partial Least Squares method upon Kriging method also known as KPLS algorithm (see Reference)
101
101
/// * GP models can be saved and loaded using [serde](https://serde.rs/).
102
- /// See `serializable` feature section below.
102
+ /// See `serializable` feature section below.
103
103
///
104
104
/// # Features
105
105
///
@@ -517,19 +517,18 @@ impl<F: Float, Mean: RegressionModel<F>, Corr: CorrelationModel<F>> GaussianProc
517
517
let x = & ( x. to_owned ( ) . insert_axis ( Axis ( 0 ) ) ) ;
518
518
let xnorm = ( x - & self . xt_norm . mean ) / & self . xt_norm . std ;
519
519
let dx = pairwise_differences ( & xnorm, & self . xt_norm . data ) ;
520
-
521
520
let sigma2 = self . inner_params . sigma2 ;
522
521
let r_chol = & self . inner_params . r_chol ;
523
522
524
523
let r = self . params . corr . value ( & dx, & self . theta , & self . w_star ) ;
525
524
let dr =
526
525
self . params
527
526
. corr
528
- . jacobian ( & xnorm. row ( 0 ) , & self . xt_norm . data , & self . theta , & self . w_star )
529
- / & self . xt_norm . std . to_owned ( ) . insert_axis ( Axis ( 0 ) ) ;
527
+ . jacobian ( & xnorm. row ( 0 ) , & self . xt_norm . data , & self . theta , & self . w_star ) ;
530
528
531
529
// rho1 = Rc^-1 . r(x, X)
532
530
let rho1 = r_chol. solve_triangular ( & r, UPLO :: Lower ) . unwrap ( ) ;
531
+
533
532
// inv_kr = Rc^t^-1 . Rc^-1 . r(x, X) = R^-1 . r(x, X)
534
533
let inv_kr = r_chol. t ( ) . solve_triangular ( & rho1, UPLO :: Upper ) . unwrap ( ) ;
535
534
@@ -569,12 +568,11 @@ impl<F: Float, Mean: RegressionModel<F>, Corr: CorrelationModel<F>> GaussianProc
569
568
570
569
// p4 = (B^-1 . A)^t . dA/dx^t = A^t . B^-1 . dA/dx^t = p3
571
570
let p4 = d_mat. t ( ) . dot ( & d_a. t ( ) ) ;
572
-
573
571
let two = F :: cast ( 2. ) ;
574
- let prime_t = ( -p2 + p4 ) . mapv ( |v| two * v) . t ( ) . to_owned ( ) ;
572
+ let prime = ( p4 - p2 ) . mapv ( |v| two * v) ;
575
573
576
574
let x_std = & self . xt_norm . std ;
577
- let dvar = ( prime_t / x_std) . mapv ( |v| v * sigma2) ;
575
+ let dvar = ( prime / x_std) . mapv ( |v| v * sigma2) ;
578
576
dvar. row ( 0 ) . into_owned ( )
579
577
}
580
578
@@ -693,6 +691,7 @@ where
693
691
}
694
692
695
693
/// Gausssian Process adaptator to implement `linfa::Predict` trait for variance prediction.
694
+ #[ allow( dead_code) ]
696
695
pub struct GpVariancePredictor < ' a , F , Mean , Corr > ( & ' a GaussianProcess < F , Mean , Corr > )
697
696
where
698
697
F : Float ,
@@ -1091,7 +1090,7 @@ mod tests {
1091
1090
use super :: * ;
1092
1091
use approx:: { assert_abs_diff_eq, assert_abs_diff_ne} ;
1093
1092
use argmin_testfunctions:: rosenbrock;
1094
- use egobox_doe:: { Lhs , SamplingMethod } ;
1093
+ use egobox_doe:: { Lhs , LhsKind , SamplingMethod } ;
1095
1094
use linfa:: prelude:: Predict ;
1096
1095
#[ cfg( not( feature = "blas" ) ) ]
1097
1096
use linfa_linalg:: norm:: Norm ;
@@ -1436,7 +1435,7 @@ mod tests {
1436
1435
paste! {
1437
1436
1438
1437
#[ test]
1439
- fn [ <test_gp_variance_derivatives_ $regr: snake _ $corr: snake>] ( ) {
1438
+ fn [ <test_gp_variance_derivatives_ $regr: snake _ $corr: snake _ $func : snake >] ( ) {
1440
1439
let mut rng = Xoshiro256Plus :: seed_from_u64( 42 ) ;
1441
1440
let xt = egobox_doe:: Lhs :: new( & array![ [ -$limit, $limit] , [ -$limit, $limit] ] ) . with_rng( rng. clone( ) ) . sample( $nt) ;
1442
1441
let yt = [ <$func>] ( & xt) ;
@@ -1602,15 +1601,88 @@ mod tests {
1602
1601
1603
1602
fn assert_rel_or_abs_error ( y_deriv : f64 , fdiff : f64 ) {
1604
1603
println ! ( "analytic deriv = {y_deriv}, fdiff = {fdiff}" ) ;
1605
- if fdiff. abs ( ) < 2e-1 || y_deriv . abs ( ) < 2e -1 {
1606
- let atol = 2e -1;
1604
+ if fdiff. abs ( ) < 6e -1 {
1605
+ let atol = 6e -1;
1607
1606
println ! ( "Check absolute error: abs({y_deriv}) should be < {atol}" ) ;
1608
1607
assert_abs_diff_eq ! ( y_deriv, 0.0 , epsilon = atol) ; // check absolute when close to zero
1609
1608
} else {
1610
- let rtol = 3e -1;
1609
+ let rtol = 6e -1;
1611
1610
let rel_error = ( y_deriv - fdiff) . abs ( ) / fdiff. abs ( ) ; // check relative
1612
1611
println ! ( "Check relative error: {rel_error} should be < {rtol}" ) ;
1613
1612
assert_abs_diff_eq ! ( rel_error, 0.0 , epsilon = rtol) ;
1614
1613
}
1615
1614
}
1615
+
1616
+ fn sin_linear ( x : & Array2 < f64 > ) -> Array2 < f64 > {
1617
+ // sin + linear trend
1618
+ let x1 = x. column ( 0 ) . to_owned ( ) . mapv ( |v| v. sin ( ) ) ;
1619
+ let x2 = x. column ( 0 ) . mapv ( |v| 2. * v) + x. column ( 1 ) . mapv ( |v| 5. * v) ;
1620
+ ( x1 + x2)
1621
+ . mapv ( |v| v + 10. )
1622
+ . into_shape ( ( x. nrows ( ) , 1 ) )
1623
+ . unwrap ( )
1624
+ }
1625
+
1626
+ #[ test]
1627
+ fn test_bug_var_derivatives ( ) {
1628
+ let _xt = egobox_doe:: Lhs :: new ( & array ! [ [ -5. , 10. ] , [ -5. , 10. ] ] )
1629
+ . kind ( LhsKind :: Centered )
1630
+ . sample ( 12 ) ;
1631
+ let _yt = sin_linear ( & _xt) ;
1632
+
1633
+ let xt = array ! [
1634
+ [ 6.875 , -4.375 ] ,
1635
+ [ -3.125 , 1.875 ] ,
1636
+ [ 1.875 , -1.875 ] ,
1637
+ [ -4.375 , 3.125 ] ,
1638
+ [ 8.125 , 9.375 ] ,
1639
+ [ 4.375 , 4.375 ] ,
1640
+ [ 0.625 , 0.625 ] ,
1641
+ [ 9.375 , 6.875 ] ,
1642
+ [ 5.625 , 8.125 ] ,
1643
+ [ -0.625 , -3.125 ] ,
1644
+ [ 3.125 , 5.625 ] ,
1645
+ [ -1.875 , -0.625 ]
1646
+ ] ;
1647
+ let yt = array ! [
1648
+ [ 2.43286801 ] ,
1649
+ [ 13.10840811 ] ,
1650
+ [ 5.32908578 ] ,
1651
+ [ 17.81862219 ] ,
1652
+ [ 74.08849877 ] ,
1653
+ [ 39.68137781 ] ,
1654
+ [ 14.96009727 ] ,
1655
+ [ 63.17475741 ] ,
1656
+ [ 61.26331775 ] ,
1657
+ [ -7.46009727 ] ,
1658
+ [ 44.39159189 ] ,
1659
+ [ 2.17091422 ] ,
1660
+ ] ;
1661
+
1662
+ let gp = GaussianProcess :: < f64 , ConstantMean , SquaredExponentialCorr > :: params (
1663
+ ConstantMean :: default ( ) ,
1664
+ SquaredExponentialCorr :: default ( ) ,
1665
+ )
1666
+ . theta_tuning ( ThetaTuning :: Fixed ( vec ! [ 0.0437386 , 0.00697978 ] ) )
1667
+ . fit ( & Dataset :: new ( xt, yt) )
1668
+ . expect ( "GP fitting" ) ;
1669
+
1670
+ let e = 5e-6 ;
1671
+ let xa = -1.3 ;
1672
+ let xb = 2.5 ;
1673
+ let x = array ! [
1674
+ [ xa, xb] ,
1675
+ [ xa + e, xb] ,
1676
+ [ xa - e, xb] ,
1677
+ [ xa, xb + e] ,
1678
+ [ xa, xb - e]
1679
+ ] ;
1680
+ let y_pred = gp. predict_var ( & x) . unwrap ( ) ;
1681
+ let y_deriv = gp. predict_var_gradients ( & array ! [ [ xa, xb] ] ) ;
1682
+ let diff_g = ( y_pred[ [ 1 , 0 ] ] - y_pred[ [ 2 , 0 ] ] ) / ( 2. * e) ;
1683
+ let diff_d = ( y_pred[ [ 3 , 0 ] ] - y_pred[ [ 4 , 0 ] ] ) / ( 2. * e) ;
1684
+
1685
+ assert_abs_diff_eq ! ( y_deriv[ [ 0 , 0 ] ] , diff_g, epsilon = 1e-5 ) ;
1686
+ assert_abs_diff_eq ! ( y_deriv[ [ 0 , 1 ] ] , diff_d, epsilon = 1e-5 ) ;
1687
+ }
1616
1688
}
0 commit comments