ADVERTISEMENT

Count all binary relations

APL (Dyalog Extended), 99 93 bytes

r←0∊0 0⍉⊢
R←r~
s←⊢≢⍉
S←1∊⊢∧⍉
t←0∊⊢≥∨.∧⍨
T←1∊⊢∧∨.∧⍨
{×⍵:+/∧⌿~(⍺,'0'){(⍎⍺)⊣⍵}\⍵-⍛↑∘⊤¨,⍳⍵⍴2*⍵⋄1}

Try it online!

-5 bytes thanks to @ovs for spotting R←r~, and -1 by taking the boolean negation of the intermediate results.

Takes the condition as a string, using the abbreviation as follows:

r: reflexive
R: irreflexive
s: symmetric
S: asymmetric
t: transitive
T: antitransitive

For example, reflexive + symmetric + transitive is given as 'rst' and "no condition" is given as ''.

How it works (before golfing)

⍝ Each of rRsStT takes an adjacency matrix and determines if the condition is met

⍝ reflexive: the diagonal is all ones
r←∧/0 0⍉⊢
⍝ irreflexive: the diagonal is all zeros
R←∧/0 0⍉~
⍝ symmetric: transpose is equal to self
s←⊢≡⍉
⍝ antisymmetric: each position in self and transpose cannot be both ones
S←~1∊⊢∧⍉
⍝ transitive: self includes the transitive square of self
t←~0∊⊢≥∨.∧⍨
⍝ antitransitive: each position in self and transitive square cannot be both ones
T←~1∊⊢∧∨.∧⍨

⍝ main function
{×⍵:+/∧⌿(⍺,'≡'){(⍎⍺)⍵}\⍵-⍛↑∘⊤¨,⍳⍵⍴2*⍵⋄1}  ⍝ ⍵: n, ⍺: conditions
{×⍵: ... ⋄1}  ⍝ Take 0 as a special case, always returning 1
,⍳⍵⍴2*⍵       ⍝ Generate all length-n vectors of 0..2^n-1
⍵-⍛↑∘⊤¨       ⍝ Convert them to n×n binary matrices
(⍺,'≡')       ⍝ Add a default function that always returns 1 to the list of conditions
{...}\        ⍝ Take outer product of conditions and matrices...
 (⍎⍺)⍵        ⍝ Eval the condition function and apply it to the matrix
+/∧⌿          ⍝ Count the matrices which satisfy all the conditions

JavaScript (Node.js), 182 bytes

A slower but significantly shorter version suggested by @tsh.

Expects (n)(m), where n is a BigInt and m is a list of constraints among:

IRREFLEXIVE = 0, REFLEXIVE = 1, ANTISYMMETRIC = 2,
SYMMETRIC = 3, ANTITRANSITIVE = 4, TRANSITIVE = 5
n=>m=>eval("g=(c,x=n)=>x?c(--x)&g(c,x):1;h=(x,y)=>!(k>>x+n*y&1n);for(t=0,k=1n<<n*n;k--;)t+=m.every(q=>g(x=>g(y=>g(z=>[h(x,x)^q,h(x,y)|h(y,x)^q%2,h(x,y)|h(y,z)|h(x,z)^q%2][q>>1]))))")

Try it online! (part 1)
Try it online! (part 2)


JavaScript (Node.js), 215 bytes

Expects (n)(m), where n is a BigInt and m is a bit-mask describing which constraints are enabled, using a combination of:

IRREFLEXIVE    = 1
REFLEXIVE      = 2
ANTISYMMETRIC  = 4
SYMMETRIC      = 8
ANTITRANSITIVE = 16
TRANSITIVE     = 32
n=>m=>{g=(c,x=n)=>x?c(--x)&g(c,x):1;h=(x,y)=>!(k>>x+n*y&1n);for(t=0,k=1n<<n*n;k--;)t+=![x=>h(x,x)^q,0,x=>g(y=>h(x,y)|h(y,x)^q),0,x=>g(y=>g(z=>h(x,y)|h(y,z)|h(x,z)^q)),0].some((c,j)=>m>>j&!g((q=j&1)?C:C=c));return t}

Try it online!

Notes:

  • To get a much faster version, replace the first bitwise & with &&.
  • Using BigInts is slower and slightly longer, but allows this code to work for any n in theory.

Formatted and commented

n => m => {
  // helper function to test whether c(x) is true for all x in [0 .. n - 1]
  g = (c, x = n) => x ? c(--x) & g(c, x) : 1;

  // helper function to test if (x, y) is *not* in S
  h = (x, y) => !(k >> x + n * y & 1n);

  // we use k = 2 ** n² - 1 to k = 0 to describe all possible binary relations
  // (k is essentially a flatten binary matrix of size n x n)
  for(t = 0, k = 1n << n * n; k--;)
    // increment t if ...
    t +=
      // ... the following tests are all falsy
      ![
        // irreflexive (q = 0) / reflexive (q = 1)
        x => h(x, x) ^ q, 0,

        // antisymmetric (q = 0) / symmetric (q = 1)
        x => g(y => h(x, y) | h(y, x) ^ q), 0,

        // antitransitive (q = 0) / transitive (q = 1)
        x => g(y => g(z => h(x, y) | h(y, z) | h(x, z) ^ q)), 0
      ]
      .some((c, j) =>
        // return true if the constraint is set ...
        m >> j &
        // ... and the test fails
        !g((q = j & 1) ? C : C = c)
      );
  return t
}

Python 3, 319 bytes

Expects to be called as f(n, m), where m is a bitmask of which conditions are required, in the same order as the question.

r=lambda x:x and r(x[1:])+[x[:1]+a for a in r(x[1:])]or[[]]
f=lambda n,c:(lambda z:n==0 or sum(1for a in map(set,r([(x,y)for x in z for y in z]))if not(lambda g,h,i:(g<=a)+(a-g==a)*2+(h==a)*4+(a-h==a)*8+(i|a==a)*16+(a-i==a)*32)(set(zip(z,z)),{(q,b)for(b,q)in a},{(d,c)for(d,b)in a for(l,c)in a if l==b})&c^c))(range(n))

Try it online!