int
main (
int                 argc,
char *              argv[])
{
  SCOTCH_Graph          grafdat;
  SCOTCH_Strat          stradat;
  SCOTCH_Num            baseval;
  SCOTCH_Num            partnbr;
  SCOTCH_Num            partnum;
  SCOTCH_Num * restrict parttax;
  SCOTCH_Num            vertnbr;
  SCOTCH_Num            vertnum;
  SCOTCH_Num *          verttab;
  SCOTCH_Num *          vendtab;
  SCOTCH_Num *          velotab;
  SCOTCH_Num *          vlbltab;
  SCOTCH_Num *          edgetax;
  SCOTCH_Num * restrict flagtab;
  SCOTCH_Num * restrict loadtab;
  SCOTCH_Num            loadmin;
  SCOTCH_Num            loadmax;
  SCOTCH_Num            loadsum;
  double                loadavg;
  FILE *                fileptr;

  SCOTCH_errorProg (argv[0]);

  if ((argc < 4) || (argc > 5)) {
    SCOTCH_errorPrint ("usage: %s nparts input_source_graph_file output_mapping_file [strategy]", argv[0]);
    exit (EXIT_FAILURE);
  }

  if ((partnbr = (SCOTCH_Num) atoi (argv[1])) < 1) {
    SCOTCH_errorPrint ("main: invalid number of parts (\"%s\")", argv[1]);
    exit (EXIT_FAILURE);
  }

  if (SCOTCH_stratInit (&stradat) != 0) {
    SCOTCH_errorPrint ("main: cannot initialize strategy");
    exit (EXIT_FAILURE);
  }
  if (argc == 5) {
    if (SCOTCH_stratGraphPartOvl (&stradat, argv[4]) != 0) {
      SCOTCH_errorPrint ("main: invalid user-provided strategy");
      exit (EXIT_FAILURE);
    }
  }

  if (SCOTCH_graphInit (&grafdat) != 0) {
    SCOTCH_errorPrint ("main: cannot initialize graph");
    exit (EXIT_FAILURE);
  }

  if ((fileptr = fopen (argv[2], "r")) == NULL) {
    SCOTCH_errorPrint ("main: cannot open file (1)");
    exit (EXIT_FAILURE);
  }

  if (SCOTCH_graphLoad (&grafdat, fileptr, -1, 0) != 0) {
    SCOTCH_errorPrint ("main: cannot load graph");
    exit (EXIT_FAILURE);
  }

  fclose (fileptr);

  SCOTCH_graphData (&grafdat, &baseval, &vertnbr, &verttab, &vendtab, &velotab, &vlbltab, NULL, &edgetax, NULL);

  if (((parttax = malloc (vertnbr * sizeof (SCOTCH_Num))) == NULL) ||
      ((flagtab = malloc (partnbr * sizeof (SCOTCH_Num))) == NULL) ||
      ((loadtab = malloc (partnbr * sizeof (SCOTCH_Num))) == NULL)) {
    SCOTCH_errorPrint ("main: out of memory");
    exit (EXIT_FAILURE);
  }

  if (SCOTCH_graphPartOvl (&grafdat, partnbr, &stradat, parttax) != 0) { /* Parttax is not based yet */
    SCOTCH_errorPrint ("main: cannot compute mapping");
    exit (EXIT_FAILURE);
  }

  edgetax -= baseval;
  parttax -= baseval;

  memset (loadtab,  0, partnbr * sizeof (SCOTCH_Num)); /* Part loads set to 0                */
  memset (flagtab, ~0, partnbr * sizeof (SCOTCH_Num)); /* Flags set to invalid vertex number */

  for (vertnum = 0; vertnum < vertnbr; vertnum ++) {
    SCOTCH_Num          veloval;
    SCOTCH_Num          partval;

    veloval = (velotab == NULL) ? 1 : velotab[vertnum];
    partval = parttax[vertnum + baseval];         /* vertnum is not based               */
    if (partval >= 0)                             /* If vertex belongs to one part only */
      loadtab[partval] += veloval;                /* Add vertex load to this part       */
    else {                                        /* Vertex belongs to several parts    */
      SCOTCH_Num          edgenum;

      for (edgenum = verttab[vertnum]; edgenum < vendtab[vertnum]; edgenum ++) {
        SCOTCH_Num          vertend;
        SCOTCH_Num          partend;

        vertend = edgetax[edgenum];
        partend = parttax[vertend];               /* vertend is based                     */
        if (partend < 0)                          /* If neighbor has no identifiable part */
          continue;
        if (flagtab[partend] == vertnum)          /* If neighbor part already accounted for, skip it */
          continue;

        loadtab[partend] += veloval;              /* Vertex load contributes to this part */
        flagtab[partend]  = vertnum;              /* Record a contribution has been made  */
      }
    }
  }

  loadsum =
  loadmax = 0;
  loadmin = SCOTCH_NUMMAX;
  for (partnum = 0; partnum < partnbr; partnum ++) {
    loadsum += loadtab[partnum];
    if (loadtab[partnum] > loadmax)
      loadmax = loadtab[partnum];
    if (loadtab[partnum] < loadmin)
      loadmin = loadtab[partnum];

    printf ("M\tCompload[%02ld]\t%ld\n",
            (long) partnum,
            (long) loadtab[partnum]);
  }

  loadavg = (double) loadsum / (double) partnbr;
  printf ("M\tCompLoadAvg\t%g\n",
	  (double) loadavg);
  printf ("M\tCompLoadMax/Avg\t%g\n",
	  (double) loadmax / loadavg);

  if ((fileptr = fopen (argv[3], "w")) == NULL) {
    SCOTCH_errorPrint ("main: cannot open file (2)");
    exit (EXIT_FAILURE);
  }

  if (fprintf (fileptr, "%ld\n", (long) vertnbr) == EOF) {
    SCOTCH_errorPrint ("main: bad output (1)");
    exit (EXIT_FAILURE);
  }

  for (vertnum = 0; vertnum < vertnbr; vertnum ++) {
    if (fprintf (fileptr, "%ld\t%ld\n",
                 (long) ((vlbltab == NULL) ? vertnum : vlbltab[vertnum]),
                 (long) parttax[vertnum + baseval]) == EOF) {
      SCOTCH_errorPrint ("main: bad output (2)");
      exit (EXIT_FAILURE);
    }
  }

  fclose (fileptr);

  free (loadtab);
  free (flagtab);
  free (parttax + baseval);

  SCOTCH_stratExit (&stradat);
  SCOTCH_graphExit (&grafdat);

  exit (EXIT_SUCCESS);
}
/**************************************/

/*
**
*/

FORTRAN (                                       \
SCOTCHFGRAPHPARTOVL, scotchfgraphpartovl, (     \
SCOTCH_Graph * const        grafptr,            \
const SCOTCH_Num * const    partptr,            \
SCOTCH_Strat * const        straptr,            \
SCOTCH_Num * const          parttab,            \
int * const                 revaptr),           \
(grafptr, partptr, straptr, parttab, revaptr))
{
  *revaptr = SCOTCH_graphPartOvl (grafptr, *partptr, straptr, parttab);
}

/* String lengths are passed at the very
** end of the argument list.
*/

FORTRAN (                                             \
SCOTCHFSTRATGRAPHPARTOVL, scotchfstratgraphpartovl, ( \
SCOTCH_Strat * const        straptr,                  \
const char * const          string,                   \
int * const                 revaptr,                  \
const int                   strnbr),                  \
(straptr, string, revaptr, strnbr))
{
  char * restrict     strtab;                     /* Pointer to null-terminated string */