Це код OVSF?


27

Давши список 1s і -1s, визначте, чи це дійсний код OVSF (вивівши значення truthy або falsey).

Коди OVSF визначаються наступним чином:

  • [1] є кодом OVSF.

  • Якщо Xє OVSF-код, то X ++ Xі X ++ -Xобидва є кодами OVSF.

    Тут ++відбувається конкатенація списку та -заперечує кожен елемент у списку.

  • Жоден інший список не є дійсними кодами OVSF.

Ви можете припустити, що список вхідних даних містить лише -1та 1, але ви повинні правильно обробити порожній список, а також списки, довжина яких не має потужності 2.

Найкоротший код (у байтах) виграє.

Тестові справи

[] -> False
[1] -> True
[-1] -> False
[1, 1] -> True
[1, -1] -> True
[1, 1, 1, 1] -> True
[1, 1, 1, 1, 1] -> False
[1, -1, -1, 1, -1, 1, 1, -1] -> True
[1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1] -> False
[1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1] -> False
[1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1] -> True

5
Що означає "OVSF"?
NoOneIsHere

5
Ортогональний коефіцієнт розповсюдження змінних , який стосується способу їх використання, а також корисного властивості, яке вони мають. Це не здавалося дуже актуальним, але посилання у Вікіпедії пояснює все це (неясно).
Лінн

Відповіді:


8

Желе , 18 16 14 11 байт

^2/Eam2µḊ¿Ṭ

Виходи [1](truthy) для OVSF-кодів, [](фальшиві) в іншому випадку.

Спробуйте в Інтернеті!

Фон

Як @ MATL відповіді LuisMendo в і @ XNOR Відповість Python , це уявлення перевіряє вхідний масив «від навиворіт».

Кожна пара елементів, що не перекриваються, коду OVSF довжиною дві або більше - це, по суті, копія першої пари або з однаковими знаками, або з обома знаками, поміненими. Аналогічно, кожен (неперекривається) 4-х елементів елементів OVSF-коду довжиною чотири або вище є по суті копією першого 4-х кортежа, або з однаковими знаками, або з обома знаками, поміненими в заміну. Те саме стосується 8-кортежів, 16-кортежів тощо, аж до довжини коду OVFS.

Один із способів перевірити це - перевірити спочатку всі пари на рівність за модулем знаку, а потім видалити другий елемент кожної пари (що тепер є зайвою інформацією). Якщо ми повторимо цей процес ще раз, ми по суті перевіряємо всі 4-кортежі. У наступній ітерації ми порівнюємо 8-кортежі тощо.

Нарешті, якщо всі необхідні 2 k -пари були рівними за модулем, знак і масив було зменшено до одинарного, достатньо перевірити, чи залишився елемент 1 .

Як це працює

^2/Eam2µḊ¿Ṭ  Main link. Argument: A (array of 1's and -1's)

       µḊ¿   While dequeuing A (removing its first element) yields a non-empty
             array, execute the monadic chain to the left, updating A with the
             return value after each iteration.
^2/            Compute the bitwise XOR of each non-overlapping pair of elements of
               A. Note that 1 ^ 1 = 0 = -1 ^ -1 and 1 ^ -1 = -2 = -1 ^ 1.
               For an array of even length that consists of the same pairs modulo
               the sign, this returns either an array of 0's or an array of -2's.
               If the length is odd, it will also contain the last element, which
               is either a 1 or a -1.
   E           Test the elements of the result for equality. This yields 1 if the
               array consists solely of 0's or solely of -2's, 0 otherwise.
    a          Take the logical AND of the previous result and every element of A.
               This returns A if it passed the previous test, but replaces all of
               its elements with 0's otherwise.
     m2        Modulo 2; select every second element of A, starting with the first.
             At this point, the last return value can be:
               • [  ] if the input was empty
               • [ 1] if the input was a valid OVSF code
               • [-1] if the input was the negative of a valid OVSF code.
               • [ 0] in all other cases.
           Ṭ  Untruth; yield an array with 1's at the specified indices.
              Indexing is 1-based in Jelly, so [1] returns [1], the array with a 1
              at index 1. Since the indices -1 and 0 are non-canonical, the arrays
              [-1] and [0] are mapped to []. The empty array remains empty.

14

Математика, 52 47 45 байт

Кількість байтів передбачає кодування CP-1252 і $CharacterEncodingвстановлено значення WindowsANSI(за замовчуванням в установках Windows).

±___=!(±1=1>0)
a__±b__/;a!==b!||{a}==-{b}:=±a

Це визначає варіативну функцію PlusMinus, яка приймає список вхідних даних як плоский список аргументів і повертає булевий, наприклад, PlusMinus[1, -1, -1, 1]дає True. Це теоретично також можна використовувати в якості оператора ±, але оператор тільки синтаксично діє в одинарних і подвійних контекстах, тому угода про виклики б отримати дивно: ±##&[1,-1,-1,1]. Це кине купу попереджень, які можна ігнорувати.

Це також викличе кілька попереджень, які можна ігнорувати.

Можливо, не вдасться скоротити дещо дратівливу a!==b!||{a}==-{b}частину, але я зараз нічого не знаходжу. Ключові слова на кшталт SubsetQі MatrixRankпросто занадто довгі. : /

Пояснення

Рішення, в основному, відкладає всі складні речі в узгоджувачі шаблонів Mathematica і тому є дуже декларативним за стилем. Окрім деякої кількості гольфу на першому рядку, це дійсно лише додає три різні визначення для оператора ±:

±___=False;
±1=True;
a__±b__/;a!==b!||{a}==-{b}:=±a

Перші два ряди були скорочені шляхом введення визначень і вираження Trueяк 1>0.

Нам слід деконструювати це далі, щоб показати, як це насправді визначає функцію variadci PlusMinus, використовуючи лише унарні та бінарні позначення оператора. Зрозуміло, що всі оператори просто синтаксичний цукор для повних виразів. У нашому випадку ±відповідає PlusMinus. Наступний код 100% еквівалентний:

PlusMinus[___]=False;
PlusMinus[1]=True;
PlusMinus[a__,b__]/;a!==b!||{a}==-{b}:=PlusMinus[a]

Використовуючи послідовності (на зразок splats на інших мовах) в якості операндів, ±ми можемо охопити довільну кількість аргументів PlusMinus, хоча ±це не можна використовувати з більш ніж двома аргументами. Основна причина полягає в тому, що синтаксичний цукор вирішується спочатку, перш ніж розширити будь-яку з цих послідовностей.

Про визначення:

Перше визначення - це просто резервний запас ( ___відповідає довільному списку аргументів). Все, що не відповідає більш конкретним визначенням нижче, дасть False.

Друге визначення - базовий випадок для OVSF, перелік містить лише цей 1. Ми визначаємо це так True.

Нарешті, третє визначення стосується лише списків, які можна розкласти на X ++ Xабо X ++ -Xрекурсивно використовувати результат для X. Визначення обмежується цими списками, гарантуючи, що вони можуть бути розділені на послідовності aта bз, a__±b__а потім приєднати умову ( /;), що {a}=={b}або {a}==-{b}. Визначення PlusMinusяк варіативної функції таким дивним способом через оператора зберігає колосальні 5 байт над визначенням унарного оператора ±у списках.

Але зачекайте, є ще більше. Ми використовуємо a!==b!замість цього {a}=={b}. Зрозуміло, що ми робимо це, бо це на два байти коротше, але цікаве питання, чому це працює. Як я пояснював вище, всі оператори - це лише синтаксичний цукор для деякого виразу з головою. {a}є List[a]. Але aце послідовність (як я вже сказав, ніби як знак на інших мовах) , так що, якщо aє , 1,-1,1то ми отримаємо List[1,-1,1]. Тепер постфікс !є Factorial. Так ось, ми б дісталися Factorial[1,-1,1]. Але Factorialне знає, що робити, коли аргумент має іншу кількість аргументів, ніж один, тому це просто залишається недооціненим. ==Не дуже важливо, якщо річ з обох сторін є списками, вона просто порівнює вирази, і якщо вони рівні, це даєTrue(у цьому випадку він фактично не дає, Falseякщо їх немає, але шаблони не збігаються, якщо умова повертає щось інше, ніж True). Тож це означає, що перевірка рівності все ще працює, якщо в списках принаймні два елементи. Що робити, якщо є лише один? Якщо так a, 1то a!все одно 1. Якщо aє, -1то a!дає ComplexInfinity. Зараз, порівняння 1з собою, все ще працює чудово, звичайно. Але ComplexInfinity == ComplexInfinityзалишається неоціненою і не відповідає дійсності, хоча a == -1 == b. На щастя, це не має значення, тому що єдиною ситуацією, в PlusMinus[-1, -1]якій виявляється, є те, що так чи інакше не є дійсним OVSF! (Якщо б стан повернувся True, про рекурсивний дзвінок буде повідомленоFalseврешті-решт, тому не має значення, що перевірка не виходить.) Ми не можемо використовувати той самий трюк для, {a}==-{b}тому що -не буде нитка Factorial, а лише нитки List.

Матч-шаблон відповідає за рештою та просто знайде правильне визначення, яке слід застосувати.


9

Haskell, 57 байт

q=length
f l=l==until((>=q l).q)(\s->s++map(*l!!q s)s)[1]

З огляду на список введення l, зростає код OVSF s, починаючи з [1]та багаторазово об'єднуючи або будь-який, sі той -s, що робить перший елемент відповідним тому, що і l. Потім перевіряє, чи є результат lв кінці. Це перевіряється, коли sмає довжину принаймні довжину l.

Деякі альтернативні рекурсивні структури також мали 57:

(s%i)l|length l<=i=s==l|j<-2*i=(s++map(*l!!i)s)%j$l
[1]%1

q=length
s%l|q s>=q l=s==l|r<-s++map(*l!!q s)s=r%l
([1]%)

q=length
g s l|q s<q l=g(s++map(*l!!q s)s)l|1>0=s==l
g[1]

6

MATLAB / Октава , 94 байти

function a=f(r);n=nnz(r);m=log2(n);a=0;if fix(m)-m==0;for c=hadamard(n);a=a+all(r==c');end;end

Це використовує новий підхід: Дозволені OVSF коди довжини Nз'являються в log2(N)Уолша-матриці , так як вони в основному залежить від того ж рекурсії:

Матриці Уолша - це особливі випадки матриць Хадамарда розміром, N x Nякщо Nпотужність дві. (Існують також матриці Адамара інших розмірів.) MATLAB та Octave мають різноманітні вбудовані функції, які генерують тестові матриці для тестування властивостей чисельних алгоритмів, серед яких є hadamard(). На щастя, для потужностей двох MATLAB hadamard()використовується саме конструкція валлійських матриць.

Таким чином, ця функція спочатку перевіряє, чи є довжина входів потужністю дві, і якщо вона є, вона перевіряє, чи це рядок відповідного розміру валійської матриці.

Спробуйте в Інтернеті!


5

Пітон, 64 байти

f=lambda l:[]<l[1::2]==[x*l[1]for x in l[::2]]*f(l[::2])or[1]==l

Розбиває список на парні елементи та парно-індексовані елементи через фрагменти. Перевіряє, чи результати векторів є рівними або негативними, множивши один на знак, вимушений його першим елементом. Потім проводить ту ж рекурсивну перевірку на парно-індексовані елементи.

У базовому випадку, якщо перевірка не вдається, відхиляє, якщо список не є [1]. Порожній список також спеціально відхиляється, щоб уникнути нескінченного циклу.

Інша стратегія, як моя відповідь Haskell, дає 66 байт:

f=lambda l,i=1,s=[1]:l[i:]and f(l,i*2,s+[x*l[i]for x in s])or s==l

2

Haskell , 106 91 87 86 байт

g n|n<1=[[1]]|m<-g(n-1)=foldl(\a b->[b++map(0-)b,b++b]++a)[]m++m
f l=elem l$g$length l

Функція gгенерує nітерацію списків (відносно неефективно, оскільки length $ g n == 3^n, хоч якби ми видалили дублікати, ми отримали б 2^n), fперевіряє, чи є наш список у будь-якому з них. Дякуємо @Zgrab за кілька підказок!

Спробуйте в Інтернеті!


Запуск двох останніх тестових випадків не дав мені результатів.
Олівер

@obarakon Так, це тому, що gце дуже неефективно і створює тонну дублікатів. (Перевірте розділ налагодження , можливо, це пов’язано з обмеженням часу або пам’яті.)
недолік

2

JavaScript (ES6), 130 93 87 85 83 байт

f=a=>(b=a.slice(0,l=a.length/2),c=a.slice(l)+"",a==1||l&&b==c|b.map(i=>-i)==c&f(b))

Демо

f=a=>(b=a.slice(0,l=a.length/2),c=a.slice(l)+"",a==1||l&&b==c|b.map(i=>-i)==c&f(b)),[[],[1],[-1],[1,1],[1,-1],[1,1,1,1],[1,1,1,1,1],[1,-1,-1,1,-1,1,1,-1],[1,1,1,1,-1,-1,-1,-1,1,1,1,1],[1,1,1,1,-1,-1,-1,-1,1,1,1,1,1,1,1,1],[1,1,1,1,-1,-1,-1,-1,1,1,1,1,-1,-1,-1,-1]].map(a=>console.log(`[${a}] -> ${!!f(a)}`))


2

JavaScript (ES6), 85 61 байт

a=>(l=a.length)&&!(l&l-1)&a.every((e,i)=>e==a[j=i&-i]*a[i-j])

Попередня версія, яка перевіряла елементи, щоб переконатися, що вони були 1чи -1:

a=>(l=a.length)&&!(l&l-1)&a.every((e,i)=>i?(j=i&-i)<i?e==a[j]*a[i-j]:e==1|e==-1:e==1)

Пояснення:

  • Довжина не може дорівнювати нулю
  • Довжина повинна бути потужністю 2
  • Перший елемент повинен бути 1
  • Елементи в позиціях, потужність яких 2, повинні бути або 1, або -1
  • Елементи в інших позиціях - це добуток усіх елементів у положеннях, відповідних біт-масці, наприклад a[22] == a[2] * a[4] * a[16]. Оскільки a[20] == a[4] * a[16]вже перевірено, a[22] == a[2] * a[20]потрібно лише перевірити.
  • Вищевказана перевірка дає вироджені результати за iвідсутність принаймні двох біт. Якщо встановлено нульовий біт, він перевіряє a[0] == a[0] * a[0], що невірно a[0] == -1, тоді як у випадку одного набору бітів це перевіряє a[i] == a[0] * a[i].

Ви можете змінити, (l=a.length)&&!(l&l-1)щоб (l=a.length)&-l==lзберегти 4 байти
Патрік Робертс

@PatrickRoberts Це не правда l==0?
Ніл

О, ти маєш рацію. Ну тоді (l=a.length)&&l&-l==l? щоб зберегти 1 байт ...
Патрік Робертс

Насправді, [1,1,1,1,-1,-1,-1,-1,1,1,1,1,1,1,1,1]незважаючи ні на що , ваша функція не спрацьовує навіть без моїх пропозицій.
Патрік Робертс

@PatrickRoberts l&-l==lне працює, оскільки ==має більшу перевагу ніж &. І тестовий випадок не працює через помилку помилки, яка коштуватиме мені байта, щоб виправити.
Ніл

2

MATL , 21 20 байт

`2eZ}yy=&=tn1>hh]1X=

Спробуйте в Інтернеті! Або перевірити всі тестові випадки .

Як це працює

Код розбиває масив на дві частини однакової довжини: перша з непарними індексованими записами, друга з парними індексованими записами. Два шматки змушені мати однакову довжину, з нульовим прокладкою в другому, якщо потрібно. Потім код перевіряє це

  1. Відповідні записи двох творів або всі рівні, або всі різні;
  2. Жоден запис у другому творі не дорівнює нулю;
  3. Довжина шматочків перевищує 1.

Якщо ці три умови будуть виконані, процес застосовується знову на першому фрагменті. Якщо цикл вийшов з-за того, що довжина була вже 1, введенням є код OFSV. Інакше це не так.

Умова 1 повторена - це еквівалентна версія визначальної властивості кодів OVSF. Для масиву довжини сказати 8 прямим підходом було б перевірити, чи всі записи 1,2,3,4 є рівними або всі відрізняються до записів 5,6,7,8 відповідно (це визначальна властивість). Але ми можемо еквівалентно перевірити, чи всі записи 1,3,5,7 рівні або всі різні відповідно 2,4,6,8; і, виявляється, використовується менше байтів.

Умова 2 гарантує, що вхідна довжина є потужністю 2: якщо її немає, на деякому етапі буде введений нульовий наконечник.

`        % Do...while loop
  2e     %   Reshape as a two-row matrix, with a padding zero if needed
         %   Row 1 contains the original odd-indexed entries, row 2 the
         %   even-indexed
  Z}     %   Split matrix into two vectors, one corresponding to each row
  yy     %   Duplicate those two vectors
  =      %   Check if corresponding entries are equal or not
  &=     %   Matrix of all pairwise comparisons. This will give a matrix
         %   filled with ones if and only if the previous check gave all
         %   true or all false (condition 1)
  tn1>   %   Duplicate and push true if size exceeds 1, or false otherwise
         %   (condition 3)
  hh     %   Concatenate condition 1, condition 3, and the original copy of
         %   the second piece (condition 2). The resulting vector is truthy
         %   if and only if it doesn't contain any zero
]        % End
1X=      % True if top of the stack is a single 1, false otherwise

2

Haskell, 66 байт

Так, нескінченні списки!

o=[1]:(o>>= \x->[x++map(0-)x,x++x])
f l=l`elem`take(2*2^length l)o

Альтернативні версії:

o=[1]:(o<**>map(>>=flip(++))[map(0-),id])
f=Data.List.Ordered.hasBy(comparing length)o

Дякую за (0-)хитрість, я застряг у negateабо((-1)*)
Бергі

1

APL, 46 байт

{0::0⋄⍵≡,1:1⋄⍬≡⍵:0⋄(∇Z↑⍵)∧(∇Y)∨∇-Y←⍵↓⍨Z←.5×⍴⍵}

Досить прямо:

  • Базові корпуси:
    • 0::0: якщо сталася помилка, поверніть 0
    • ⍵≡,1:1: якщо введення точно [1], поверніть 1
    • ⍬≡⍵:0: якщо вхід є порожнім списком, поверніть 0
  • Рекурсивний випадок:
    • Z←.5×⍴⍵: Z- половина довжини вводу
    • Y←⍵↓⍨Z: Y- остання половина вводу (ця помилка ⍴⍵нерівна, запускає обробник винятків)
    • (∇Y)∨∇-Y: або остання половина списку, або заперечення останньої половини списку повинні бути кодом OVSF
    • (∇Z↑⍵)∧: і перша половина списку повинна бути кодом OVSF.

1
Я не думаю, що достатньо перевірити OVSF-кодовість на другу половину; вона повинна дорівнювати першій половині або її запереченню.
Згарб

1
вони кажуть, що BASIC - це високий рівень туги, а APL - це високий рівень туги: ')
кіт

вони кажуть, що BASIC - це високий рівень туги, а APL - це високий рівень туги: ')
кіт

1

Haskell, 69 68 байт

g x=any(elem x)$scanr(\_->concat.mapM(\y->[y++y,y++map(0-)y]))[[1]]x

Приклад використання: g [-1,1]-> False.

Ще більш неефективна, ніж відповідь @ flawr . Це вимагає занадто багато часу і пам'яті для 4-х списків елементів. Щоб побачити, що список OVSF-кодів (з великою кількістю дублікатів) фактично створений, спробуйте:

take 10 $ c $ scanr(\_->concat.mapM(\y->[y++y,y++map(0-)y]))[[1]] [1..4]

який повертається

[[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
 [1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1],
 [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
 [1,-1,-1,1,1,-1,-1,1,1,-1,-1,1,1,-1,-1,1],
 [1,1,-1,-1,1,1,-1,-1,1,1,-1,-1,1,1,-1,-1],
 [1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1],
 [1,1,-1,-1,1,1,-1,-1,1,1,-1,-1,1,1,-1,-1],
 [1,-1,-1,1,1,-1,-1,1,1,-1,-1,1,1,-1,-1,1],
 [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
 [1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1]]

тобто список починається зі всіх 16-ти списків елементів (через 4 рази об'єднаних [1..4]), продовжується всіма 8-ми списками елементів і так далі, поки не закінчується [1].

Редагувати: @xnor зберег байт. Спасибі!


Ах, я зовсім забув scanr!
дефект

Я думаю, ви можете вирізати байт, роблячи any(elem x)замість цього, elem x$cа не визначаючи c.
xnor


0

JavaScript (ES6), 80

f=(l,k=[1])=>l+l==k+k||l[k.length]&&f(l,k.concat(k))|f(l,k.concat(k.map(v=>-v)))

Рекурсивно будує та перевіряє кожен список до довжини списку введення, починаючи з [1].

Значення, що повертається JS truthy або falsey, в зокрема , 1чи trueякщо дійсно, 0чи , falseабо , undefinedякщо не діє.

Тест

f=(l,k=[1])=>l+l==k+k||l[k.length]&&f(l,k.concat(k))|f(l,k.concat(k.map(v=>-v)))

test=`[] -> False
[1] -> True
[-1] -> False
[1, 1] -> True
[1, -1] -> True
[1, 1, 1, 1] -> True
[1, 1, 1, 1, 1] -> False
[1, -1, -1, 1, -1, 1, 1, -1] -> True
[1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1] -> False
[1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1] -> False
[1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1] -> True`
.split('\n')

test.forEach(r=>{
  input = r.match(/-?1/g)||[]
  check = r.slice(-4) == 'True'
  result = f(input)
  console.log(result, check, '['+input+']')
})


0

Clojure, 118 байт

(defn f[C](or(=(count C)1)(let[l(/(count C)2)[a b](split-at l C)](and(> l 0)(=(count b)l)(apply =(map * a b))(f a)))))

Розбиває введення cна дві половини aі bперевіряє, чи всі їх елементи, що відповідають елементам, однакові. Якщо так, перевірте, чи є правильним послідовність першого тайму.

Цей 142 байти, але мені здалося, що це цікавіше:

#((set(nth(iterate(fn[I](mapcat(fn[i][(concat i i)(concat i(map - i))])I))[[1][-1]])(loop[l(count %)i 0](if(< l 2)i(recur(/ l 2)(inc i))))))%)

loopобчислює log_2довжину введення, iterateгенерує послідовності цих багатьох ітерацій на основі визначення. Це повертає вхідний аргумент, якщо це дійсна послідовність та nilінше.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.