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!