arb/arb_calc/isolate_roots.c
2019-02-12 09:22:08 +01:00

184 lines
4.7 KiB
C

/*
Copyright (C) 2013 Fredrik Johansson
This file is part of Arb.
Arb is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. See <http://www.gnu.org/licenses/>.
*/
#include "arb_calc.h"
#define BLOCK_NO_ZERO 0
#define BLOCK_ISOLATED_ZERO 1
#define BLOCK_UNKNOWN 2
static int
check_block(arb_calc_func_t func, void * param, const arf_interval_t block,
int asign, int bsign, slong prec)
{
arb_struct t[2];
arb_t x;
int result;
arb_init(t + 0);
arb_init(t + 1);
arb_init(x);
arf_interval_get_arb(x, block, prec);
func(t, x, param, 1, prec);
result = BLOCK_UNKNOWN;
if (arb_is_positive(t) || arb_is_negative(t))
{
result = BLOCK_NO_ZERO;
}
else
{
if ((asign < 0 && bsign > 0) || (asign > 0 && bsign < 0))
{
func(t, x, param, 2, prec);
if (arb_is_finite(t + 1) && !arb_contains_zero(t + 1))
{
result = BLOCK_ISOLATED_ZERO;
}
}
}
arb_clear(t + 0);
arb_clear(t + 1);
arb_clear(x);
return result;
}
#define ADD_BLOCK \
if (*length >= *alloc) \
{ \
slong new_alloc; \
new_alloc = (*alloc == 0) ? 1 : 2 * (*alloc); \
*blocks = flint_realloc(*blocks, sizeof(arf_interval_struct) * new_alloc); \
*flags = flint_realloc(*flags, sizeof(int) * new_alloc); \
*alloc = new_alloc; \
} \
arf_interval_init((*blocks) + *length); \
arf_interval_set((*blocks) + *length, block); \
(*flags)[*length] = status; \
(*length)++; \
static void
isolate_roots_recursive(arf_interval_ptr * blocks, int ** flags,
slong * length, slong * alloc,
arb_calc_func_t func, void * param,
const arf_interval_t block, int asign, int bsign,
slong depth, slong * eval_count, slong * found_count,
slong prec)
{
int status;
if (*found_count <= 0 || *eval_count <= 0)
{
status = BLOCK_UNKNOWN;
ADD_BLOCK
}
else
{
*eval_count -= 1;
status = check_block(func, param, block, asign, bsign, prec);
if (status != BLOCK_NO_ZERO)
{
if (status == BLOCK_ISOLATED_ZERO || depth <= 0)
{
if (status == BLOCK_ISOLATED_ZERO)
{
if (arb_calc_verbose)
{
flint_printf("found isolated root in: ");
arf_interval_printd(block, 15);
flint_printf("\n");
}
*found_count -= 1;
}
ADD_BLOCK
}
else
{
arf_interval_t L, R;
int msign;
arf_interval_init(L);
arf_interval_init(R);
msign = arb_calc_partition(L, R, func, param, block, prec);
if (msign == 0 && arb_calc_verbose)
{
flint_printf("possible zero at midpoint: ");
arf_interval_printd(block, 15);
flint_printf("\n");
}
isolate_roots_recursive(blocks, flags, length, alloc,
func, param,
L, asign, msign,
depth - 1, eval_count, found_count, prec);
isolate_roots_recursive(blocks, flags, length, alloc,
func, param,
R, msign, bsign,
depth - 1, eval_count, found_count, prec);
arf_interval_clear(L);
arf_interval_clear(R);
}
}
}
}
slong
arb_calc_isolate_roots(arf_interval_ptr * blocks, int ** flags,
arb_calc_func_t func, void * param,
const arf_interval_t block, slong maxdepth, slong maxeval, slong maxfound,
slong prec)
{
int asign, bsign;
slong length, alloc;
arb_t m, v;
*blocks = NULL;
*flags = NULL;
length = 0;
alloc = 0;
arb_init(m);
arb_init(v);
arb_set_arf(m, &block->a);
func(v, m, param, 1, prec);
asign = arb_sgn_nonzero(v);
arb_set_arf(m, &block->b);
func(v, m, param, 1, prec);
bsign = arb_sgn_nonzero(v);
arb_clear(m);
arb_clear(v);
isolate_roots_recursive(blocks, flags, &length, &alloc,
func, param, block, asign, bsign,
maxdepth, &maxeval, &maxfound, prec);
*blocks = flint_realloc(*blocks, length * sizeof(arf_interval_struct));
*flags = flint_realloc(*flags, length * sizeof(int));
return length;
}