#include "ca.h"
#include "ca/impl.h"
#include "ca_ext.h"
#include "ca_field.h"
#include "ca_vec.h"
void
ca_conj_shallow(ca_t res, const ca_t x, ca_ctx_t ctx)
{
if (CA_IS_SPECIAL(x))
{
ca_unknown(res, ctx);
}
else if (CA_IS_QQ(x, ctx))
{
ca_set(res, x, ctx);
}
else if (CA_IS_QQ_I(x, ctx))
{
ca_set(res, x, ctx);
fmpz_neg(QNF_ELEM_NUMREF(CA_NF_ELEM(res)) + 1, QNF_ELEM_NUMREF(CA_NF_ELEM(res)) + 1);
}
else
{
_ca_make_field_element(res, _ca_ctx_get_field_fx(ctx, CA_Conjugate, x), ctx);
fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx));
}
}
void
ca_set_ext(ca_t res, ca_ext_srcptr ext, ca_ctx_t ctx)
{
if (CA_EXT_HEAD(ext) == CA_QQBar)
{
ca_field_srcptr field;
field = ca_ctx_get_field_qqbar(ctx, CA_EXT_QQBAR(ext));
_ca_make_field_element(res, field, ctx);
nf_elem_gen(CA_NF_ELEM(res), CA_FIELD_NF(field));
}
else
{
ca_field_ptr K;
ca_ext_struct * X[1];
X[0] = (ca_ext_ptr) ext;
K = ca_field_cache_insert_ext(CA_CTX_FIELD_CACHE(ctx), X, 1, ctx);
_ca_make_field_element(res, K, ctx);
fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx));
}
}
static void
ca_conj_ext(ca_t res, ca_ext_ptr ext, ca_ctx_t ctx)
{
slong p;
ulong q;
switch (CA_EXT_HEAD(ext))
{
case CA_QQBar:
if (qqbar_is_real(CA_EXT_QQBAR(ext)))
{
ca_set_ext(res, ext, ctx);
}
else if (qqbar_is_i(CA_EXT_QQBAR(ext)))
{
ca_neg_i(res, ctx);
}
else if (qqbar_sgn_re(CA_EXT_QQBAR(ext)) == 0)
{
ca_field_srcptr field;
field = ca_ctx_get_field_qqbar(ctx, CA_EXT_QQBAR(ext));
_ca_make_field_element(res, field, ctx);
nf_elem_gen(CA_NF_ELEM(res), CA_FIELD_NF(field));
nf_elem_neg(CA_NF_ELEM(res), CA_NF_ELEM(res), CA_FIELD_NF(field));
}
else if (qqbar_is_root_of_unity(&p, &q, CA_EXT_QQBAR(ext)))
{
ca_field_srcptr field;
nf_struct * nf;
field = ca_ctx_get_field_qqbar(ctx, CA_EXT_QQBAR(ext));
nf = CA_FIELD_NF(field);
_ca_make_field_element(res, field, ctx);
nf_elem_gen(CA_NF_ELEM(res), CA_FIELD_NF(field));
nf_elem_pow(CA_NF_ELEM(res), CA_NF_ELEM(res), q - 1, nf);
ca_condense_field(res, ctx);
}
else
{
qqbar_t t;
qqbar_init(t);
qqbar_conj(t, CA_EXT_QQBAR(ext));
ca_set_qqbar(res, t, ctx);
qqbar_clear(t);
}
break;
case CA_Pi:
case CA_Euler:
case CA_Re:
case CA_Im:
case CA_Abs:
case CA_Arg:
case CA_Floor:
case CA_Ceil:
ca_set_ext(res, ext, ctx);
break;
case CA_Sqrt:
case CA_Log:
case CA_LogGamma:
if (ca_check_is_negative_real(CA_EXT_FUNC_ARGS(ext), ctx) != T_FALSE)
{
ca_set_ext(res, ext, ctx);
ca_conj_shallow(res, res, ctx);
}
else if (ca_check_is_real(CA_EXT_FUNC_ARGS(ext), ctx) == T_TRUE)
{
ca_set_ext(res, ext, ctx);
}
else
{
ca_t t;
ca_init(t, ctx);
ca_conj_deep(t, CA_EXT_FUNC_ARGS(ext), ctx);
_ca_make_field_element(res, _ca_ctx_get_field_fx(ctx, CA_EXT_HEAD(ext), t), ctx);
fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx));
ca_clear(t, ctx);
}
break;
case CA_Pow:
if (ca_check_is_negative_real(CA_EXT_FUNC_ARGS(ext) + 0, ctx) != T_FALSE)
{
ca_set_ext(res, ext, ctx);
ca_conj_shallow(res, res, ctx);
}
else if (ca_check_is_real(CA_EXT_FUNC_ARGS(ext) + 0, ctx) == T_TRUE &&
ca_check_is_real(CA_EXT_FUNC_ARGS(ext) + 1, ctx) == T_TRUE)
{
ca_set_ext(res, ext, ctx);
}
else
{
ca_t t, u;
ca_init(t, ctx);
ca_init(u, ctx);
ca_conj_deep(t, CA_EXT_FUNC_ARGS(ext) + 0, ctx);
ca_conj_deep(u, CA_EXT_FUNC_ARGS(ext) + 1, ctx);
_ca_make_field_element(res, _ca_ctx_get_field_fxy(ctx, CA_Pow, t, u), ctx);
fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx));
ca_clear(t, ctx);
ca_clear(u, ctx);
}
break;
case CA_Exp:
case CA_Sin:
case CA_Cos:
case CA_Tan:
case CA_Cosh:
case CA_Sinh:
case CA_Tanh:
case CA_Gamma:
case CA_RiemannZeta:
case CA_Erf:
case CA_Erfc:
case CA_Erfi:
{
if (ca_check_is_real(CA_EXT_FUNC_ARGS(ext), ctx) == T_TRUE)
{
ca_set_ext(res, ext, ctx);
}
else
{
ca_t t;
ca_init(t, ctx);
ca_conj_deep(t, CA_EXT_FUNC_ARGS(ext), ctx);
_ca_make_field_element(res, _ca_ctx_get_field_fx(ctx, CA_EXT_HEAD(ext), t), ctx);
fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx));
ca_clear(t, ctx);
}
}
break;
default:
ca_set_ext(res, ext, ctx);
ca_conj_shallow(res, res, ctx);
}
}
static void nf_elem_conj_imag(nf_elem_t a, const nf_elem_t b, const nf_t nf)
{
nf_elem_set(a, b, nf);
if (nf->flag & NF_LINEAR)
{
}
else if (nf->flag & NF_QUADRATIC)
{
fmpz_neg(QNF_ELEM_NUMREF(a) + 1, QNF_ELEM_NUMREF(a) + 1);
}
else
{
slong i;
for (i = 1; i < NF_ELEM(a)->length; i += 2)
fmpz_neg(NF_ELEM(a)->coeffs + i, NF_ELEM(a)->coeffs + i);
}
}
void
ca_conj_deep(ca_t res, const ca_t x, ca_ctx_t ctx)
{
if (CA_IS_SPECIAL(x))
{
ca_unknown(res, ctx);
}
else if (CA_IS_QQ(x, ctx))
{
ca_set(res, x, ctx);
}
else if (CA_IS_QQ_I(x, ctx))
{
ca_set(res, x, ctx);
fmpz_neg(QNF_ELEM_NUMREF(CA_NF_ELEM(res)) + 1, QNF_ELEM_NUMREF(CA_NF_ELEM(res)) + 1);
}
else
{
ca_field_ptr K;
slong p;
ulong q;
K = CA_FIELD(x, ctx);
if (CA_FIELD_IS_NF(K))
{
if (qqbar_is_real(CA_EXT_QQBAR(CA_FIELD_EXT_ELEM(K, 0))))
{
ca_set(res, x, ctx);
}
else if (qqbar_sgn_re(CA_EXT_QQBAR(CA_FIELD_EXT_ELEM(K, 0))) == 0)
{
ca_set(res, x, ctx);
nf_elem_conj_imag(CA_NF_ELEM(res), CA_NF_ELEM(res), CA_FIELD_NF(K));
}
else if (ca_is_cyclotomic_nf_elem(&p, &q, x, ctx))
{
nf_struct * nf;
fmpq_poly_t poly;
nf = CA_FIELD_NF(CA_FIELD(x, ctx));
fmpq_poly_init(poly);
nf_elem_get_fmpq_poly(poly, CA_NF_ELEM(x), nf);
ca_set(res, x, ctx);
nf_elem_gen(CA_NF_ELEM(res), nf);
nf_elem_pow(CA_NF_ELEM(res), CA_NF_ELEM(res), q - 1, nf);
ca_condense_field(res, ctx);
ca_fmpq_poly_evaluate(res, poly, res, ctx);
fmpq_poly_clear(poly);
}
else
{
fmpq_poly_t poly;
qqbar_t t;
qqbar_init(t);
fmpq_poly_init(poly);
nf_elem_get_fmpq_poly(poly, CA_NF_ELEM(x), CA_FIELD_NF(K));
qqbar_conj(t, CA_EXT_QQBAR(CA_FIELD_EXT_ELEM(K, 0)));
ca_set_qqbar(res, t, ctx);
ca_fmpq_poly_evaluate(res, poly, res, ctx);
qqbar_clear(t);
fmpq_poly_clear(poly);
}
}
else
{
slong nvars;
int * used;
slong i;
ca_ptr cext;
nvars = CA_FIELD_LENGTH(K);
used = flint_calloc(nvars, sizeof(int));
cext = _ca_vec_init(nvars, ctx);
fmpz_mpoly_q_used_vars(used, CA_MPOLY_Q(x), CA_FIELD_MCTX(K, ctx));
for (i = 0; i < nvars; i++)
{
if (used[i])
{
ca_conj_ext(cext + i, CA_FIELD_EXT_ELEM(K, i), ctx);
}
}
ca_fmpz_mpoly_q_evaluate(res, CA_MPOLY_Q(x), cext, CA_FIELD_MCTX(K, ctx), ctx);
_ca_vec_clear(cext, nvars, ctx);
flint_free(used);
}
}
}
void
ca_conj(ca_t res, const ca_t x, ca_ctx_t ctx)
{
if (CA_IS_SPECIAL(x))
{
ca_unknown(res, ctx);
}
else if (CA_IS_QQ(x, ctx))
{
ca_set(res, x, ctx);
}
else if (CA_IS_QQ_I(x, ctx))
{
ca_set(res, x, ctx);
fmpz_neg(QNF_ELEM_NUMREF(CA_NF_ELEM(res)) + 1, QNF_ELEM_NUMREF(CA_NF_ELEM(res)) + 1);
}
else if (ca_check_is_real(x, ctx) == T_TRUE)
{
ca_set(res, x, ctx);
}
else if (ca_check_is_imaginary(x, ctx) == T_TRUE)
{
ca_neg(res, x, ctx);
}
else
{
ca_conj_deep(res, x, ctx);
}
}