/*
 * @progname       graph_stats.ll
 * @version        1.0
 * @author         Jim Eggert
 * @category       
 * @output         Text
 * @description    

Calculates individual relationship graph statistics.  A typical relationship has two directed edges
(e.g., father to son and son to father).  Occasionally a relationship might have four directed edges
(e.g., a husband marrying the same wife more than once), but all relationships should have an even
number of edges.

This program outputs the number of nodes (individuals), directed edges, and lists all relationships
(pairs of individuals) connected by a number of directed edges not equal to zero or two.

Version 1, 15 May 2020

*/

proc main() {
  set(edges, 0)
  set(nodes, 0)
  table(edgetable)
  list(edgelist)
  forindi(person, ip) {
    incr(nodes)
    set(pkey, key(person))
    fornodes(inode(person), node) { /* look for relations */
      if (index(" FAMS FAMC ", upper(tag(node)), 1)) { /* found a family, value is 2 or 7 */
        fornodes(fnode(fam(value(node))), subnode) {                      /* look for other family members */
          if (index(" HUSB  WIFE  CHIL ", upper(tag(subnode)), 1)) { /* found a family member */
	    set(subpkey, key(indi(value(subnode))))
	    if (strlen(subpkey)) {
	      if (nestr(pkey, subpkey)) {
	        incr(edges)
	        if (lt(strcmp(pkey, subpkey),0)) {
	          set(edgename, concat(pkey, " ", subpkey))
	        } else {
	          set(edgename, concat(subpkey, " ", pkey))
	        }
	        if (edgecount, lookup(edgetable, edgename)) {
	          insert(edgetable, edgename, add(edgecount, 1))
	        } else {
	          insert(edgetable, edgename, 1)
		  enqueue(edgelist, edgename)
		}
	      }
	    }
	  }
	}
      }
    }
  }
  print("Database has ", d(nodes), " and ", d(edges), " directed edges.  (Typically one relationship is two directed edges.)\n")
  forlist(edgelist, edgename, en) {
    set(edgenum, lookup(edgetable, edgename))
    if (ne(edgenum, 2)) {
      if (mod(edgenum, 2)) { print("***") }
      print("Relationship ", edgename, " has ", d(edgenum), " directed edges.\n")
    }
  }
}
