// egr.h : declaration of functions for reduction of points & component groups
//////////////////////////////////////////////////////////////////////////
//
// Copyright 1990-2023 John Cremona
// 
// This file is part of the eclib package.
// 
// eclib is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version.
// 
// eclib is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
// 
// You should have received a copy of the GNU General Public License
// along with eclib; if not, write to the Free Software Foundation,
// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
// 
//////////////////////////////////////////////////////////////////////////
 
// allow for multiple includes
#ifndef _ECLIB_EGR_H_
#define _ECLIB_EGR_H_

#include <eclib/curve.h>

// class to handle component groups at primes of bad reduction etc

// NB all of the internal methods assume that the curve is a global
// minimal model.  The normal use of the class will be via the
// function egr_index() which handles computation of a minimal model
// and transferring the points to the minimal model where necessary,

class ComponentGroups : public CurveRed {
public:
  explicit ComponentGroups(const Curvedata& CD) : CurveRed(CD) {;}
  explicit ComponentGroups(const CurveRed& CR) : CurveRed(CR) {;}
  //  ComponentGroups(const Curve& C) : CurveRed(C) {;}
  ComponentGroups() : CurveRed() {;}

// return 1 iff P mod p is nonsingular for all p (including infinity);
// else return 0 and put the first prime of bad reduction into p0:
  int HasGoodReduction(const Point& P, bigint& p0) const
  {
    return P.has_good_reduction(the_bad_primes, p0, 1);
  }

// Returns [m] for cyclic of order m, [2,2] for 2*2 (type I*m, m even)
  vector<int> ComponentGroup(const bigint& p) const;

// Returns 1 iff P and Q have same image in the component group at p:
  int InSameComponent(const Point& P, const Point& Q, const bigint& p) const;

// For reduction type Im, multiplicative reduction where component
// group is cyclic of order m, returns a such that P mod p maps to a
// mod m in the component group 

// N.B.1 This will always return a in the range [0..m/2] and CANNOT
// distinguish between P and -P!  Be warned!

// N.B.2 The case of noncyclic component group is not handled here.

  long ImageInComponentGroup(const Point&P, const bigint& p, vector<int> grp) const;
  long ImageInComponentGroup_Im(const Point&P, const bigint& p, int m) const;
  long ImageInComponentGroup_Im_pm(const Point&P, const bigint& p, int m) const;

// Return least j>0 such that j*P has good reduction at p, i.e. the
// order of the image of P in the component group at p; the component
// group is given
  int OrderInComponentGroup(const Point& P, const bigint& p, vector<int> grp);

// replace (independent) points in Plist with a new set which spans
// the subgroup of the original with good reduction at p, returning
// the index
  int gr1prime(vector<Point>& Plist, const bigint& p);

// replace (independent) points in Plist with a new set which spans
// the subgroup of the original with good reduction at all p in plist,
// returning the overall index
  int grprimes(vector<Point>& Plist, const vector<bigint>& plist);

// replace (independent) points in Plist with a new set which spans
// the subgroup of the original with good reduction at all p,
// returning the overall index
  int grprimes(vector<Point>& Plist) {return grprimes(Plist,the_bad_primes);}

// replaces the (independent) points with a new set which spans the
// subgroup of the original with good reduction at all p,
// returning the overall index
  int egr_subgroup(vector<Point>& Plist, int real_too=1);
};

// returns the index in the subgroup generated by the given points of
// its egr subgroup (the points are unchanged)
bigint egr_index(const vector<Point>& Plist, int real_too=1);

// Given a list of points P1,...,Pn and a prime p, this returns a
// vector [c1,c2,...,cn] where the image of Pi in the component group
// is ci mod m, where m is the exponent of the component group at p.
// 
// Each ci is a vector of length 1 or 2 (the latter for when the
// component group is C2xC2), not just an integer.
//
// If p=0 then m=1 or 2 (m=2 iff there are two real components and at
// least one P_i is not in the connected component)
//

vector<vector<int> >  MapPointsToComponentGroup(const ComponentGroups& CG, const vector<Point>& Plist,  const bigint& p);

#endif
