Quandle Quandary Episode I: Определение конечных квандлов

20

Напишите программу, которая определит, представляет ли данная матрица квандл. Quandle представляет собой набор оснащен одной (некоммутативном, неассоциативная) операциями ◃ , которая удовлетворяет следующие аксиомы:

  • Операция закрыта, это означает, что a◃b = cвсегда является элементом множества if aи bявляются элементами множества.
  • Операция является правой-самораспределительной (a◃b)◃c = (a◃c)◃(b◃c).
  • Операция делится справа: для любой выбранной пары aи bсуществует один уникальный, cтакой, чтоc◃a = b
  • Операция идемпотентна: a◃a = a

Конечный квандл может быть представлен в виде квадратной матрицы. Ниже приведен пример квандла порядка 5 ( источник ).

0 0 1 1 1
1 1 0 0 0
3 4 2 4 3
4 2 4 3 2
2 3 3 2 4

Значение, расположенное в n-й строке и m-м столбце (0-индексированное), является значением n◃m. Например, в этом квандле 4◃1 = 3. Некоторые свойства квандла легко увидеть из этой матрицы:

  • Он закрыт, потому что в этой матрице 5x5 отображаются только значения 0-4.
  • Он идемпотентен, потому что диагональ матрицы равна 0 1 2 3 4
  • Это делится справа, потому что ни один столбец не содержит повторяющихся значений. (Строки могут и обычно будут.)

Свойство права-самораспределения сложнее проверить. Там может быть ярлык, но самый простой метод состоит в том, чтобы перебрать каждую возможную комбинацию из трех индексов, чтобы проверить это m[m[a][b]][c] = m[m[a][c]][m[b][c]].

вход

Входными данными будет список строк квадратной матрицы, использующий либо 0-индексирование, либо 1-индексирование (на ваш выбор). Каждая запись будет представлять собой однозначное число от 0до 8(или 1через 9). Я буду гибким в формате ввода. Некоторые приемлемые форматы включают в себя:

  • Наиболее естественное форматирование вашего языка для матриц или списков, таких как [[0 0 0][2 1 1][1 2 2]]или (0,0,0,2,1,1,1,2,2).
  • Список значений, разделенных пробелами, символами новой строки, запятыми и т. Д.
  • Одна строка, состоящая из всех значений, соединенных вместе, таких как 000211122.

Вы также можете использовать транспонирование матрицы в качестве входных данных (замена строк на столбцы). Просто обязательно укажите это в своем ответе.

Выход

Единственное значение truey / falsey, указывающее статус матрицы как квандл.

Примеры квандл

0

0 0
1 1

0 0 0
2 1 1
1 2 2

0 0 1 1
1 1 0 0
3 3 2 2
2 2 3 3

0 3 4 1 2
2 1 0 4 3
3 4 2 0 1
4 2 1 3 0
1 0 3 2 4

Примеры не-квандл

не закрыто

1

0 0 0
2 1 1
1 9 2

не право-самораспределительный

0 0 1 0
1 1 0 1
2 3 2 2
3 2 3 3

(3◃1)◃2 = 2◃2 = 2
(3◃2)◃(1◃2) = 3◃0 = 3

делится не правильно

0 2 3 4 1
0 1 2 3 4
3 4 2 2 2
3 3 3 3 3
4 1 1 1 4

0 1 2 3
3 1 2 0
3 1 2 3
0 1 2 3

не идемпотент

1 1 1 1
3 3 3 3
2 2 2 2
0 0 0 0

2 1 0 4 3
3 4 2 0 1
4 2 1 3 0
1 0 3 2 4
0 3 4 1 2
PhiNotPi
источник
1
Слово «матрица» вводит в заблуждение, потому что это не имеет ничего общего с линейной алгеброй. «Стол» был бы лучше (или, может быть, «Стол Кейли», но я думаю, что строго это подходит только для группы).
Питер Тейлор

Ответы:

7

Python 2 , 104 103 102 байта

t=input();e=enumerate
[0%(a==A[a]in B>C[B[a]]==t[C[b]][C[a]])for(a,A)in e(t)for(b,B)in e(t)for C in t]

Ввод транспонирован. Вывод осуществляется через код выхода, поэтому 0 (успех) является правдой, а 1 (сбой) ложным.

Попробуйте онлайн!

Как это устроено

e(t)возвращает нумерованные строки входной матрицы t, представляющей оператор as, в виде пар (индекс, строка). for(a,A)in e(t)Например, итерирует по ним, сохраняя индекс в a и саму строку в A , поэтому Aстановится ярлыком для t[a].

Между первым for(b,B)in e(t)и for C in t, мы перебираем все возможные упорядоченные кортежи (a, b, c) в декартовой степени t 3 .

Для каждого из этих кортежей мы оцениваем выражение

0%(a==A[a]in B>C[B[a]]==t[C[b]][C[a]])

Значение заключенного в скобки логического значения равно False, если и только если одно или несколько из следующих отдельных сравнений делают то же самое.

  • a==A[a]потерпит неудачу (для некоторого значения a ), если не идемпотентен.

  • A[a]in Bпотерпит неудачу , если B не содержит все показатели А .

    Поскольку A имеет n индексов, а B имеет n элементов, отсутствие ошибок означает, что элементы B соответствуют индексам A , поэтому closed замкнут и делится справа.

  • B>C[B[a]] это тавтология, так как Python 2 считал числа «меньшими», чем итерируемые.

  • C[B[a]]==t[C[b]][C[a]]потерпит неудачу для некоторого значения, если not не является самораспределительным справа.

Если какое-либо из сравнений возвращает False , выражение (0%...)выдаст ZeroDivisionError . Кроме того, если not не закрыт A[a]или C[b]может также выдать ошибку IndexError . В обоих случаях программа завершает работу с кодом состояния 1 (ошибка).

Если все тесты пройдены, программа нормально завершит работу с кодом состояния 0 (успех).

Деннис
источник
6

Haskell, 100 байт

Этот ответ использует транспонированный ввод.

q m=and$(elem<$>v<*>m)++[a#a==a&&a#b#c==a#c#(b#c)|a<-v,b<-v,c<-v]where v=[0..length m-1];i#j=m!!j!!i

Похоже, я не могу использовать шаблонную охрану для привязки инфиксного оператора, поэтому я использую whereв этом случае.

(Первая версия была 108 байтов, но пропущена проверка идемпотентности, фиксированная версия была 120 байтов, более поздние версии имели 108, 103 и 98 байтов, но мне пришлось понять, благодаря @nimi, что они все были неправы: конечно, мне нужно сделать правильно тест делимости (который подразумевает замкнутость) перед выполнением каких-либо опасных !!операций, но я все еще мог использовать большинство моих более поздних идей игры в гольф, и еще с одним, это было 102 байта, теперь улучшенное путем изменения порядка операнда #(который в любом случае лучше, чтобы компенсировать транспонирование), чтобы лучше использовать его связывание слева)

Используйте как это:

*Main> q [[0,1,2,3],[0,1,3,2],[1,0,2,3],[0,1,2,3]]
False
Кристиан Сиверс
источник
4

JavaScript (ES6), 150 байт

a=>!(a.some((b,i)=>b[i]-i)|a.some(b=>[...new Set(b)].sort()+''!=[...b.keys()])||a.some((_,i)=>a.some((_,j)=>a.some((b,k)=>b[a[j][i]]-a[b[j]][b[i]]))))

Принимает входные данные как массив массивов столбцов целых чисел.

Нил
источник
3

Mathematica, 122 байта

(n_±m_:=#[[m,n]];#&@@Union[Sort/@#]==Range@l==Array[#±#&,l=Length@#]&&And@@Flatten@Array[±##2±#==(#2±#)±(#3±#)&,{l,l,l}])&

Чистая функция принимает 2D массив целых чисел (1-индексированных) в качестве входных данных, причем строки и столбцы обращенной от конвенции в вопросе, и возвращение Trueили False. Первая строка определяет двоичную инфиксную операцию n_±m_как операцию quandle.

Для массива lx lзамкнутое и делимое справа эквивалентно тому, что каждая строка (в моем случае) является некоторой перестановкой {1, ..., l}, а идемпотент эквивалентен главной диагонали, являющейся точно {1, ..., l}. Так #&@@Union[Sort/@#]==Range@l==Array[#±#&,l=Length@#]обнаруживает эти три условия. (Использование Sort/@#здесь, почему я решил поменять строки и столбцы.)

Для правораспределительного мы буквально проверяем все возможности, используя Array[±##2±#==(#2±#)±(#3±#)&,{l,l,l}]). (Обратите внимание, что ±##2±#автоматически расширяется до (#2±#3)±#, поскольку ##2представляет последовательность второго и третьего аргументов для функции с тремя переменными pure, над которой выполняется массив.) Затем &&And@@Flatten@проверяется, был ли пройден каждый отдельный тест. Для некоторых незамкнутых квандлов могут возникать ошибки, когда он пытается получить доступ к части матрицы, которая не существует, но правильный ответ по-прежнему возвращается.

Грег Мартин
источник
±m__:=#[[m]];Я думаю. И есть Diagonalвстроенный. И ±лево-ассоциативный , так что вы можете использовать #2±#±(#3±#), но если бы я не сделал ошибку , то он короче переназначить #на #3и делать #±#2±#3==#±#3±±##2&. И это также должно быть возможно заменить всю Flatten@часть(...&~Array~{l,l,l}<>"")
Мартин Эндер
Интересно, если вам нужно переместить l=Lengthв Range@lхотя, потому что это должно быть оценено в первую очередь, так что если вы используете функцию несколько раз, я думаю, Rangeвсе еще получает предыдущее l, нет?
Мартин Эндер
0

C ++ 14, 175 байт

Как и безымянная лямбда, при условии, что nона похожа std::vector<std::vector<int>>и возвращается через ссылочный параметр. 0 ложно, все остальное верно.

#define F(x);for(x=-1;++x<s;){
[](auto m,int&r){int s=r=m.size(),a,b,c F(a)auto A=m[a];r*=s==A.size()&&A[a]==a;int u=0 F(b)u|=1<<m[b][a];r*=A[b]<s F(c)r*=m[A[b]][c]==m[A[c]][m[b][c]];}}r*=!(u-(1<<s)+1);}}

Ungolfed и использование:

#include<vector>
#include<iostream>

auto f=
#define F(x);for(x=-1;++x<s;){
[](auto m,int&r){
 int s=r=m.size(),a,b,c
 F(a)
  auto A=m[a];               //shortcut for this row
  r*=s==A.size()&&A[a]==a;   //square and idempotet
  int u=0                    //bitset for uniqueness in col
  F(b)
   u|=1<<m[b][a];            //count this item
   r*=A[b]<s                 //closed
   F(c)
    r*=m[A[b]][c]==m[A[c]][m[b][c]];
   }
  }
  r*=!(u-(1<<s)+1);          //check right-divisibility
 }
}
;

int main(){
 int r;
 std::vector<std::vector<int>>
  A = {
   {0, 0, 1, 1},
   {1, 1, 0, 0},
   {3, 3, 2, 2},
   {2, 2, 3, 3},
  },
  B = {
   {0, 2, 3, 4, 1},
   {0, 1, 2, 3, 4},
   {3, 4, 2, 2, 2},
   {3, 3, 3, 3, 3},
   {4, 1, 1, 1, 4},
  };
 f(A,r);
 std::cout << r << "\n";
 f(B,r);
 std::cout << r << "\n";
}
Карл Напф
источник
Предлагайте int a,b,c,u,s=r=m.size()Fвместо int s=r=m.size(),a,b,c F, u=0;r*=s==A.size()&&a==A[a]Fвместо r*=s==A.size()&&A[a]==a;int u=0 F, r*=s>A[b]Fвместо r*=A[b]<s Fи ~u+(1<<s)вместоu-(1<<s)+1
потолок кошка