include "global_cardinality_low_up_closed.mzn";

par int: N;
par int: C;

set of int: VS = 1..N;
set of int: CS = -C..C;
array[VS, VS] of var CS: ES;

% for Paley graphs
set of int: STEP = %{1, 2, 3, 4, 6, 7, 8, 9, 12, 14, 16, 17, 18, 21, 24, 25, 27, 28, 32, 34, 36, 37, 42}; % 47 KO
  %{1, 35, 4, 36, 6, 38, 40, 9, 10, 11, 41, 13, 14, 15, 16, 17, 21, 23, 24, 25, 31}; % 43 KO
  %{1, 2, 4, 5, 7, 8, 9, 10, 14, 16, 18, 19, 20, 25, 28}; % 31 KO
  %{1, 2, 4, 8, 9, 13, 15, 16}; % 17 KO
  %{1, 2, 3, 4, 6, 8, 9, 12, 13, 16, 18}; % 23 KO
  %{1, 3, 4, 5, 9}; % 11 KO
  {1, 2, 4}; % 7 OK
%constraint ES[1, 2] = 1;
%constraint ES[1, 3] < 3;
%constraint ES[1, 4] = -3;

% triangular matrix
constraint forall(u in VS, v in VS where u >= v)(ES[u, v] = 0);
constraint forall(u in VS, v in VS where u < v)(ES[u, v] != 0);
%constraint forall(u in VS, v in VS)(ES[u, v] > -C);

% for Paley graphs
constraint forall(u in 1..7, s in STEP)
  (if u + s <= 7 then ES[u, u+s] > 0 else ES[(u+s-1) mod 7 + 1, u] < 0 endif);

constraint forall(u in 8..14, s in STEP)
  (if u + s <= 14 then ES[u, u+s] > 0 else ES[(u+s-1) mod 7 + 8, u] < 0 endif);

% rainbow C3
%constraint ES[4, 5] = 1;
%constraint ES[5, 6] = 2;
%constraint ES[4, 6] = -3;

% linear dominator on first three vertices
%constraint forall(v in VS where v > 3)
%  (ES[1, v] > 0 \/ ES[2, v] > 0 \/ ES[3, v] > 0);

% first edge is red
constraint ES[1, 2] = 1;
% second is green
constraint ES[2, 3] = 2;

% hamiltonian circle
constraint forall(u in VS where u >= 2)
  (ES[u-1, u] > 0);
constraint ES[1, N] < 0;

% at least three dominators
constraint forall(u in VS, v in VS, x in VS where u < v /\ v < x)
  (exists(w in VS where w != u /\ w != v /\ w != x)
    (let {
      var CS: c1 = if u < w then ES[u, w] else -ES[w, u] endif;
      var CS: c2 = if v < w then ES[v, w] else -ES[w, v] endif; 
      var CS: c3 = if x < w then ES[x, w] else -ES[w, x] endif; 
    } in c1 < 0 /\ c2 < 0 /\ c3 < 0
  ));

% blue K4 and K? (K7)
%constraint forall(v in VS, u in VS where u < v)(
%  if (u+1 = v /\ u < 7)% \/ (u+1 = v /\ u > 8)
%  then ES[u, v] = 3
%  else true %ES[u, v] != 3 /\ ES[u, v] != -3 
%  endif);

% no global sink/source
%array[int] of int: c = [-1, 0, 1];
%array[int] of int: mi = [1, 0, 1]; % out >= 1, in >= 1
%array[int] of int: ma = [N-8, 0, N-2]; % out <= N-8, in <= N-2
%constraint forall(v in VS)(global_cardinality_low_up_closed(
%  [if ES[u, v] > 0 then -1 else 1 endif | u in VS where u < v]
%  ++ [if ES[v, u] > 0 then 1 else -1 endif | u in VS where u > v], c, mi, ma));

%constraint decreasing(
%  [sum(u in VS where u < v)(if ES[u, v] > 0 then -1 else 1 endif)
%  +sum(u in VS where u > v)(if ES[v, u] > 0 then 1 else -1 endif)
%  | v in VS]);

% transitive
predicate transitive(par int: u, par int: v, par int: w) =
  let {
    var CS: c1 = if u < v then ES[u, v] else -ES[v, u] endif;
    var CS: c2 = if v < w then ES[v, w] else -ES[w, v] endif; 
    var CS: c3 = if v < w then ES[u, w] else -ES[w, u] endif
  } in (c1 > 0 /\ c1 = c2) -> c3 = c1;

constraint forall(u in VS, v in VS, w in VS where u != v /\ v != w /\ u != w)(transitive(u, v, w));

% alternatively use: first_fail
%solve :: int_search([ES[u,v] | u, v in VS], input_order, indomain_random, complete) satisfy;
solve :: int_search([ES[u,v] | u, v in VS], first_fail, indomain_random, complete)
%  minimize sum(i in VS, j in VS where i < j)(bool2int(ES[i, j] = 3) + bool2int(ES[i, j] = -3));
  satisfy;

output ["graph = {\n\t"]
  ++ [ (if c > 1 /\ u = 1 /\ v = 1 then ",\n\t" else "" endif)
    ++ (if u = 1 /\ v = 1 then show(c) ++ " : {" else "" endif)
    ++ (if abs(fix(ES[u, v])) = c then
      (if fix(ES[u, v]) > 0
        then "(" ++ show(u) ++ ", " ++ show(v) ++ "),"
        else "(" ++ show(v) ++ ", " ++ show(u) ++ ")," 
      endif) 
      else "" endif)
    ++ (if u = N /\ v = N then "}" else "" endif)
    | c in CS, u in VS, v in VS where c > 0]
  ++ ["\n}"];