/*
 * Copyright(C) 1999-2021 National Technology & Engineering Solutions
 * of Sandia, LLC (NTESS).  Under the terms of Contract DE-NA0003525 with
 * NTESS, the U.S. Government retains certain rights in this software.
 *
 * See packages/seacas/LICENSE for details
 */

#include "defs.h"    // for FALSE, TRUE
#include "smalloc.h" // for sfree, smalloc
#include "structs.h" // for vtx_data

/* Find a maximal matching in a graph using simple greedy algorithm. */
/* Randomly permute vertices, and then have each select first unmatched */
/* neighbor. */

int maxmatch2(struct vtx_data **graph,      /* array of vtx data for graph */
              int               nvtxs,      /* number of vertices in graph */
              int *             mflag,      /* flag indicating vtx selected or not */
              int               using_ewgts /* are edge weights being used? */
)
{
  extern int HEAVY_MATCH; /* encourage heavy matching edges? */
  void       randomize();

  /* First, randomly permute the vertices. */
  int *order = smalloc((nvtxs + 1) * sizeof(int));
  int *iptr  = order;
  int *jptr  = mflag;
  for (int i = 1; i <= nvtxs; i++) {
    *(++iptr) = i;
    *(++jptr) = 0;
  }
  randomize(order, nvtxs);

  int nmerged = 0;

  if (!using_ewgts || !HEAVY_MATCH) { /* Simple greedy approach. */
    for (int i = 1; i <= nvtxs; i++) {
      int vtx = order[i];
      if (mflag[vtx] == 0) { /* Not already matched. */
        /* Find first unmatched neighbor of vtx. */
        int matched = FALSE;
        for (int j = 1; j < graph[vtx]->nedges && !matched; j++) {
          int neighbor = graph[vtx]->edges[j];
          if (mflag[neighbor] == 0) { /* Found one! */
            mflag[vtx]      = neighbor;
            mflag[neighbor] = vtx;
            matched         = TRUE;
            nmerged++;
          }
        }
      }
    }
  }

  else { /* Find heavy edge to match */
    for (int i = 1; i <= nvtxs; i++) {
      int vtx = order[i];
      if (mflag[vtx] == 0) { /* Not already matched. */
        /* Find heaviest unmatched neighbor of vtx. */
        int   jsave    = 0;
        float ewgt_max = 0;
        for (int j = 1; j < graph[vtx]->nedges; j++) {
          int neighbor = graph[vtx]->edges[j];
          if (mflag[neighbor] == 0 && graph[vtx]->ewgts[j] > ewgt_max) {
            ewgt_max = graph[vtx]->ewgts[j];
            jsave    = j;
          }
        }
        if (jsave > 0) {
          int neighbor    = graph[vtx]->edges[jsave];
          mflag[vtx]      = neighbor;
          mflag[neighbor] = vtx;
          nmerged++;
        }
      }
    }
  }

  sfree(order);
  return (nmerged);
}
