--- /dev/null
+function f = himmelblau(x1, x2)
+ ##
+ ## The eponymous function defined by Himmelblau in his Applied
+ ## Nonlinear Programming, 1972.
+ ##
+ ## It has four identical local minima,
+ ##
+ ## * f(3,2) == 0
+ ##
+ ## * f(-2.805118086952745, 3.131312518250573) == 0
+ ##
+ ## * f(-3.779310253377747, -3.283185991286170) == 0
+ ##
+ ## * f(3.584428340330492, -1.848126526964404) == 0
+ ##
+ f = (x1^2 + x2 - 11)^2 + (x1 + x2^2 - 7)^2;
+end
--- /dev/null
+function f = himmelblau1(x)
+ ##
+ ## A version of the Himmelblau function which takes a column
+ ## 2-vector instead of two distinct arguments. See himmelblau.m for
+ ## more information.
+ ##
+ if (length(x) == 2)
+ f = himmelblau(x(1), x(2));
+ else
+ f = NA;
+ end
+end
--- /dev/null
+function g = himmelblau_gradient(x1,x2)
+ ##
+ ## The gradient of the Himmelblau function. See himmelblau.m for
+ ## more information.
+ ##
+ f_x1 = 4*(x1^2 + x2 - 11)*x1 + 2*x2^2 + 2*x1 - 14;
+ f_x2 = 4*(x2^2 + x1 - 7)*x2 + 2*x1^2 + 2*x2 - 22;
+ g = [f_x1; f_x2];
+end
--- /dev/null
+function g = himmelblau_gradient1(x)
+ ##
+ ## A version of the himmelblau_gradient() function which takes a
+ ## column 2-vector instead of two distinct arguments. See
+ ## himmelblau_gradient.m for more information.
+ ##
+ if (length(x) == 2)
+ g = himmelblau_gradient(x(1), x(2));
+ else
+ g = NA;
+ end
+end
--- /dev/null
+function H = himmelblau_hessian(x1, x2)
+ ##
+ ## The Hessian of the Himmelblau function. See himmelblau.m for more
+ ## information.
+ ##
+ H = zeros(2,2);
+ H(1,1) = 12*x1^2 + 4*x2 - 42;
+ H(1,2) = 4*x1 + 4*x2;
+ H(2,1) = 4*x1 + 4*x2;
+ H(2,2) = 12*x2^2 + 4*x1 - 26;
+end
--- /dev/null
+function H = himmelblau_hessian1(x)
+ ##
+ ## A version of the himmelblau_hessian() function which takes a column
+ ## 2-vector instead of two distinct arguments. See himmelblau_hessian.m
+ ## for more information.
+ ##
+ if (length(x) == 2)
+ H = himmelblau_hessian(x(1), x(2));
+ else
+ H = NA;
+ end
+end
--- /dev/null
+## The gradient should be zero at the optimal points.
+
+unit_test_equals("himmelblau_gradient(3,2) == 0", ...
+ 0, ...
+ himmelblau_gradient(3,2));
+
+x1 = -2.805118086952745;
+x2 = 3.131312518250573;
+msg = sprintf("himmelblau_gradient(%f, %f) == 0", x1, x2);
+unit_test_equals(msg, ...
+ true, ...
+ norm(himmelblau_gradient(x1, x2)) < 1e-13);
+
+x1 = -3.779310253377747;
+x2 = -3.283185991286170;
+msg = sprintf("himmelblau_gradient(%f, %f) == 0", x1, x2);
+unit_test_equals(msg, ...
+ true, ...
+ norm(himmelblau_gradient(x1, x2)) < 1e-13);
+
+x1 = 3.584428340330492;
+x2 = -1.848126526964404;
+msg = sprintf("himmelblau_gradient(%f, %f) == 0", x1, x2);
+unit_test_equals(msg, ...
+ true, ...
+ norm(himmelblau_gradient(x1, x2)) < 1e-13);
--- /dev/null
+## Test the optimal points.
+
+unit_test_equals("himmelblau(3,2) == 0", ...
+ 0, ...
+ himmelblau(3,2));
+
+x1 = -2.805118086952745;
+x2 = 3.131312518250573;
+msg = sprintf("himmelblau(%f, %f) == 0", x1, x2);
+unit_test_equals(msg, ...
+ true, ...
+ norm(himmelblau(x1, x2)) < 1e-12);
+
+x1 = -3.779310253377747;
+x2 = -3.283185991286170;
+msg = sprintf("himmelblau(%f, %f) == 0", x1, x2);
+unit_test_equals(msg, ...
+ true, ...
+ norm(himmelblau(x1, x2)) < 1e-12);
+
+x1 = 3.584428340330492;
+x2 = -1.848126526964404;
+msg = sprintf("himmelblau(%f, %f) == 0", x1, x2);
+unit_test_equals(msg, ...
+ true, ...
+ norm(himmelblau(x1, x2)) < 1e-12);