Roll skia/third_party/skcms 5a327ce..dd901e0 (1 commits)

https://skia.googlesource.com/skcms.git/+log/5a327ce..dd901e0

2018-04-27 mtklein@chromium.org simplify Gauss-Newton interface


The AutoRoll server is located here: https://skcms-skia-roll.skia.org

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+/master/autoroll/README.md

If the roll is causing failures, please contact the current sheriff, who should
be CC'd on the roll, and stop the roller if necessary.



TBR=stani@google.com

Change-Id: Ie1fd5feba47cddeba47c71dfff2dc4dae1fe12ef
Reviewed-on: https://skia-review.googlesource.com/124285
Reviewed-by: skcms-skia-autoroll <skcms-skia-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com>
Commit-Queue: skcms-skia-autoroll <skcms-skia-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com>
This commit is contained in:
skcms-skia-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com 2018-04-27 15:35:32 +00:00 committed by Skia Commit-Bot
parent be850adc53
commit cbdf5d5bff
5 changed files with 56 additions and 65 deletions

View File

@ -12,18 +12,14 @@
#include <assert.h>
#include <string.h>
bool skcms_gauss_newton_step(float (* t)(float x, const void*),
const void* t_ctx,
float (* f)(float x, const void*, const float P[3]),
const void* f_ctx,
void (*grad_f)(float x, const void*, const float P[3], float dfdP[3]),
const void* g_ctx,
bool skcms_gauss_newton_step(float (*rg)(float x, const void*, const float P[3], float dfdP[3]),
const void* ctx,
float P[3],
float x0, float x1, int N) {
// We'll sample x from the range [x0,x1] (both inclusive) N times with even spacing.
//
// We want to do P' = P + (Jf^T Jf)^-1 Jf^T r(P),
// where r(P) is the residual vector t(x) - f(x,P)
// where r(P) is the residual vector
// and Jf is the Jacobian matrix of f(), ∂r/∂P.
//
// Let's review the shape of each of these expressions:
@ -63,10 +59,8 @@ bool skcms_gauss_newton_step(float (* t)(float x, const void*),
for (int i = 0; i < N; i++) {
float x = x0 + i*dx;
float resid = t(x,t_ctx) - f(x,f_ctx,P);
float dfdP[3] = {0,0,0};
grad_f(x,g_ctx,P, dfdP);
float resid = rg(x,ctx,P, dfdP);
for (int r = 0; r < 3; r++) {
for (int c = 0; c < 3; c++) {
@ -99,9 +93,7 @@ bool skcms_gauss_newton_step(float (* t)(float x, const void*),
return true;
}
float skcms_eval_curve(float x, const void* vctx) {
const skcms_Curve* curve = (const skcms_Curve*)vctx;
float skcms_eval_curve(float x, const skcms_Curve* curve) {
if (curve->table_entries == 0) {
return skcms_TransferFunction_eval(&curve->parametric, x);
}

View File

@ -9,26 +9,20 @@
#include <stdbool.h>
// One Gauss-Newton step, tuning up to 3 parameters P to minimize [ t(x,ctx) - f(x,P) ]^2.
// One Gauss-Newton step, tuning up to 3 parameters P to minimize [ r(x,ctx) ]^2.
//
// t: target function of x to approximate
// t_ctx: any context needed for t, passed blindly into calls to t()
// f: function of x,P we're tuning to match t()
// grad_f: gradient of f() at x
// P: in-out, both your initial guess for parameters of f(), and our updated values
// rg: residual function r(x,P) to minimize, and gradient at x in dfdP
// ctx: arbitrary context argument passed to rg
// P: in-out, both your initial guess for parameters of r(), and our updated values
// x0,x1,N: N x-values to test in [x0,x1] (both inclusive) with even spacing
//
// If you have fewer than 3 parameters, set the unused P to zero, don't touch their dfdP.
//
// Returns true and updates P on success, or returns false on failure.
bool skcms_gauss_newton_step(float (* t)(float x, const void*),
const void* t_ctx,
float (* f)(float x, const void*, const float P[3]),
const void* f_ctx,
void (*grad_f)(float x, const void*, const float P[3], float dfdP[3]),
const void* g_ctx,
bool skcms_gauss_newton_step(float (*rg)(float x, const void*, const float P[3], float dfdP[3]),
const void* ctx,
float P[3],
float x0, float x1, int N);
// A target function for skcms_Curve, passed as ctx.
float skcms_eval_curve(float x, const void* ctx);
// Evaluate an skcms_Curve at x.
float skcms_eval_curve(float x, const skcms_Curve*);

View File

@ -41,24 +41,30 @@
// It's important to evaluate as f(x) as A(x^3-1) + B(x^2-1) + 1
// and not Ax^3 + Bx^2 + (1-A-B) to ensure that f(1.0f) == 1.0f.
static float eval_poly_tf(float x, const void* ctx, const float P[3]) {
const skcms_PolyTF* tf = (const skcms_PolyTF*)ctx;
static float eval_poly_tf(float x, float A, float B, float C, float D) {
return x < D ? C*x
: A*(x*x*x-1) + B*(x*x-1) + 1;
}
typedef struct {
const skcms_Curve* curve;
const skcms_PolyTF* tf;
} rg_poly_tf_arg;
static float rg_poly_tf(float x, const void* ctx, const float P[3], float dfdP[3]) {
const rg_poly_tf_arg* arg = (const rg_poly_tf_arg*)ctx;
const skcms_PolyTF* tf = arg->tf;
float A = P[0],
C = tf->C,
D = tf->D;
float B = (C*D - A*(D*D*D - 1) - 1) / (D*D - 1);
return x < D ? C*x
: A*(x*x*x-1) + B*(x*x-1) + 1;
}
static void grad_poly_tf(float x, const void* ctx, const float P[3], float dfdP[3]) {
const skcms_PolyTF* tf = (const skcms_PolyTF*)ctx;
(void)P;
float D = tf->D;
dfdP[0] = (x*x*x - 1) - (x*x-1)*(D*D*D-1)/(D*D-1);
return skcms_eval_curve(x, arg->curve)
- eval_poly_tf(x, A,B,C,D);
}
static bool fit_poly_tf(const skcms_Curve* curve, skcms_PolyTF* tf) {
@ -116,9 +122,8 @@ static bool fit_poly_tf(const skcms_Curve* curve, skcms_PolyTF* tf) {
// Start with guess A = 0, i.e. f(x) ≈ x^2.
float P[3] = {0, 0,0};
for (int i = 0; i < 3; i++) {
if (!skcms_gauss_newton_step(skcms_eval_curve, curve,
eval_poly_tf, tf,
grad_poly_tf, tf,
rg_poly_tf_arg arg = { curve, tf };
if (!skcms_gauss_newton_step(rg_poly_tf, &arg,
P,
tf->D, 1, N-L)) {
return false;
@ -127,13 +132,13 @@ static bool fit_poly_tf(const skcms_Curve* curve, skcms_PolyTF* tf) {
float A = tf->A = P[0],
C = tf->C,
D = tf->D;
tf->B = (C*D - A*(D*D*D - 1) - 1) / (D*D - 1);
D = tf->D,
B = tf->B = (C*D - A*(D*D*D - 1) - 1) / (D*D - 1);
for (int i = 0; i < N; i++) {
float x = i * (1.0f/(N-1));
float rt = skcms_TransferFunction_eval(&inv, eval_poly_tf(x, tf, P));
float rt = skcms_TransferFunction_eval(&inv, eval_poly_tf(x, A,B,C,D));
if (!isfinitef_(rt)) {
return false;
}

View File

@ -143,8 +143,17 @@ bool skcms_TransferFunction_invert(const skcms_TransferFunction* src, skcms_Tran
// ∂tf/∂b = g(ax + b)^(g-1)
// - g(ad + b)^(g-1)
static float eval_nonlinear(float x, const void* ctx, const float P[3]) {
const skcms_TransferFunction* tf = (const skcms_TransferFunction*)ctx;
typedef struct {
const skcms_Curve* curve;
const skcms_TransferFunction* tf;
} rg_nonlinear_arg;
// Return the residual of the skcms_Curve and skcms_TransferFunction with parameters P,
// and fill out the gradient of the residual into dfdP.
static float rg_nonlinear(float x, const void* ctx, const float P[3], float dfdP[3]) {
const rg_nonlinear_arg* arg = (const rg_nonlinear_arg*)ctx;
const skcms_TransferFunction* tf = arg->tf;
const float g = P[0], a = P[1], b = P[2],
c = tf->c, d = tf->d, f = tf->f;
@ -153,27 +162,19 @@ static float eval_nonlinear(float x, const void* ctx, const float P[3]) {
D = a*d+b;
assert (X >= 0 && D >= 0);
// (Notice how a large amount of this work is independent of x.)
return powf_(X, g)
- powf_(D, g)
+ c*d + f;
}
static void grad_nonlinear(float x, const void* ctx, const float P[3], float dfdP[3]) {
const skcms_TransferFunction* tf = (const skcms_TransferFunction*)ctx;
const float g = P[0], a = P[1], b = P[2],
d = tf->d;
const float X = a*x+b,
D = a*d+b;
assert (X >= 0 && D >= 0);
// The gradient.
dfdP[0] = 0.69314718f*log2f_(X)*powf_(X, g)
- 0.69314718f*log2f_(D)*powf_(D, g);
dfdP[1] = x*g*powf_(X, g-1)
- d*g*powf_(D, g-1);
dfdP[2] = g*powf_(X, g-1)
- g*powf_(D, g-1);
// The residual.
const float t = powf_(X, g)
- powf_(D, g)
+ c*d + f;
return skcms_eval_curve(x, arg->curve) - t;
}
int skcms_fit_linear(const skcms_Curve* curve, int N, float tol, float* c, float* d, float* f) {
@ -232,9 +233,8 @@ static bool fit_nonlinear(const skcms_Curve* curve, int start, int N, skcms_Tran
assert (P[1] >= 0 &&
P[1] * tf->d + P[2] >= 0);
if (!skcms_gauss_newton_step(skcms_eval_curve, curve,
eval_nonlinear, tf,
grad_nonlinear, tf,
rg_nonlinear_arg arg = { curve, tf};
if (!skcms_gauss_newton_step(rg_nonlinear, &arg,
P,
start*x_scale, 1, N-start)) {
return false;

View File

@ -1 +1 @@
5a327ce9eb094efdb75893d1ac6d46637e006f14
dd901e0921c663860c813a8bb53b25f8035bccd5