First of all, your original "intermediate value"-based code doesn't quite do what it is advertised to do:
To test whether a continuous function has a root in a given interval [x0, x1] is relatively easy: according to Intermediate value theorem when the sign of function value at x0 is opposite to the sign at x1, there is (at least) one root.
The test looks like:
if sign of g(x0) is opposite of sign of g(x1)
then return true
else return false
This "test" has one-sided error, as pointed out by David Eisenstat. If the signs are indeed opposite, then return true
is okay, but if the signs are not opposite, then return false
should perhaps be return maybe
or something...
Second of all as regards the Poincare Miranda theorem, in higher dimensions comparing the signs of a few points doesn't give you enough information to apply the theorem.
Consider n
continuous functions of n
variables. Assume that for every variable x_i
, the function f_i
is constantly negative when x_i = 0
and constantly positive when x_i = 1
. Then there is a point in the n
-dimensional unit cube in which all functions are simultaneously equal to 0
.
There is no black-box test if a continuous function is "constantly negative" on some region.
You would need to assume something more, like, you assume it is actually a low-degree polynomial and you sample it at enough points to discover its coefficients, etc.
If we assume like you stated that we have two bivariate quadratics, and we actually have (or deduce) the coefficients... it is possible.
What I would do is simply, substitute in the value for x_i
in each function as required, so it reduces to a univariate quadratic, and then solve for its roots (if any) using the quadratic formula like we learned in grade school. Then check whether they occur in the region of interest. Then test a point in-between the roots to determine the sign. Then you'll know if the theorem can be applied.
It's possible that you can solve for a precise condition in closed-form but I'm not sure if this will actually help you write a better (simpler / more efficient) implementation.
Here is some pseudocode:
def quadratic_positive_in_region(p, x_0, x_1)
ASSERT(p is univariate)
ASSERT(x_0 <= x_1)
// If one of the roots lies in the region then
// we are zero there, and thus not positive
def roots = quadratic_formula(p)
for r in roots:
if x_0 <= r and r <= x_1 then return false
// If there are no roots in the region then
// we are either always positive or always negative,
// so test a single point to determine.
if p(x_0 + x_1 / 2) > 0 then return true
return false
def poincare_miranda(g1, g2, x_0, x_1, y_0, y_1)
return quadratic_positive_in_region(-g1 | y = y_0, x_0, x_1) and
quadratic_positive_in_region( g1 | y = y_1, x_0, x_1) and
quadratic_positive_in_region(-g2 | x = x_0, y_0, y_1) and
quadratic_positive_in_region( g2 | x = x_1, y_0, y_1)
def generalized_test(g1, g2, x_0, x_1, y_0, y_1)
return poincare_miranda( g1, g2, x_0, x_1, y_0, y_1) or
poincare_miranda(-g1, g2, x_0, x_1, y_0, y_1) or
poincare_miranda(-g1, -g2, x_0, x_1, y_0, y_1) or
poincare_miranda( g1, -g2, x_0, x_1, y_0, y_1)
I'm using some notation here where -
operator can be applied to a polynomial, also |
notation represents substitution of a value for a variable in a polynomial.