È un codice OVSF?


27

Dato un elenco di 1s e -1s, determinare se si tratta di una valida codice OVSF (emettendo un truthy o un valore Falsey).

I codici OVSF sono definiti come segue:

  • [1] è un codice OVSF.

  • Se Xè un codice OVSF, allora X ++ Xe X ++ -Xsono entrambi codici OVSF.

    Ecco la ++concatenazione dell'elenco e -annulla tutti gli elementi dell'elenco.

  • Nessun altro elenco è un codice OVSF valido.

È possibile supporre che l'elenco di input contenga solo -1e 1, ma è necessario gestire correttamente l'elenco vuoto, nonché elenchi la cui lunghezza non è una potenza di 2.

Vince il codice più breve (in byte).

Casi 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

5
Cosa significa "OVSF"?
NoOneIsHere

5
Fattore di diffusione variabile ortogonale , che si riferisce al modo in cui vengono utilizzati e anche a una proprietà utile che hanno. Questo non sembra molto rilevante, ma il link di Wikipedia spiega tutto (vagamente).
Lynn,

Risposte:


8

Gelatina , 18 16 14 11 byte

^2/Eam2µḊ¿Ṭ

Output [1](veritiero) per codici OVSF, [](falsi) in caso contrario.

Provalo online!

sfondo

Come @ risposta MATL di LuisMendo e @ di xnor risposta Python , questa sottomissione verifica la matrice di input "dal fuori dentro".

Ogni coppia (non sovrapposta) di elementi di un codice OVSF di lunghezza due o superiore è essenzialmente una copia della prima coppia, con gli stessi segni o con entrambi i segni scambiati. Allo stesso modo, ogni 4 tuple (non sovrapposte) di elementi di un codice OVSF di lunghezza quattro o superiore è essenzialmente una copia della prima 4 tupla, con gli stessi segni o con entrambi i segni scambiati. Lo stesso vale per 8 tuple, 16 tuple, ecc., Fino alla lunghezza del codice OVFS.

Un modo per verificarlo è verificare prima tutte le coppie per l'uguaglianza modulo il segno, quindi rimuovere il secondo elemento di ciascuna coppia (che ora è informazione ridondante). Se ripetiamo questo processo ancora una volta, essenzialmente controlliamo tutte e 4 le tuple. Nella prossima iterazione, confronteremo 8 tuple, ecc.

Infine, se tutte le 2 k -tuple richieste erano uguali a modulo il segno e l'array è stato ridotto a un singleton, è sufficiente verificare se l'elemento rimanente è 1 .

Come funziona

^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

Mathematica, 52 47 45 byte

Il conteggio dei byte presuppone la codifica CP-1252 e $CharacterEncodingimpostato su WindowsANSI(impostazione predefinita nelle installazioni di Windows).

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

Questo definisce una funzione variadic PlusMinus, che prende lista di input come una semplice lista di argomenti e restituisce un booleano, ad esempio PlusMinus[1, -1, -1, 1]True. E 'teoricamente utilizzabile anche come operatore ±, ma l'operatore è solo sintatticamente valido in contesti unarie e binari, in modo che la convenzione di chiamata otterrebbe strano: ±##&[1,-1,-1,1]. Emetterà un mucchio di avvertimenti che possono essere ignorati.

Ciò genererà anche alcuni avvertimenti che possono essere ignorati.

Ci potrebbe essere lontano per accorciare la un po 'fastidioso a!==b!||{a}==-{b}parte, ma io non sto trovando nulla al momento. Le parole chiave piacciono SubsetQe MatrixRanksono semplicemente troppo lunghe. : /

Spiegazione

La soluzione fondamentalmente difende tutte le cose difficili per il pattern matcher di Mathematica ed è quindi molto dichiarativa nello stile. A parte un po 'di golfitude sulla prima linea, questo aggiunge solo tre diverse definizioni per l'operatore ±:

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

Le prime due righe sono state accorciate annidando le definizioni ed esprimendo Truecome 1>0.

Dovremmo decostruire ulteriormente questo per mostrare come questo in realtà definisce una funzione variadci PlusMinususando solo la notazione operatore unaria e binaria. Il trucco è che tutti gli operatori sono semplicemente zucchero sintattico per le espressioni complete. Nel nostro caso ±corrisponde a PlusMinus. Il seguente codice è equivalente al 100%:

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

Usando sequenze (una specie di splat simili in altre lingue) come operandi ±, possiamo coprire un numero arbitrario di argomenti PlusMinus, anche se ±non è utilizzabile con più di due argomenti. Il motivo fondamentale è che lo zucchero sintattico viene risolto prima, prima che una qualsiasi di queste sequenze venga espansa.

Alle definizioni:

La prima definizione è semplicemente un fallback ( ___corrisponde a un elenco arbitrario di argomenti). Tutto ciò che non corrisponde alle definizioni più specifiche seguenti fornirà False.

La seconda definizione è il caso base per OVSF, l'elenco contenente solo 1. Definiamo questo per essere True.

Infine, la terza definizione si applica solo agli elenchi che possono essere scomposti in X ++ Xo X ++ -Xe ricorsivamente utilizza il risultato per X. La definizione è limitata a questi elenchi garantendo che possano essere suddivisi in sottosequenze ae bcon a__±b__e quindi allegando la condizione ( /;) che {a}=={b}o {a}==-{b}. La definizione PlusMinuscome funzione variadica in questo strano modo tramite un operatore salva un enorme 5 byte rispetto alla definizione di un operatore unario ±sugli elenchi.

Ma aspetta, c'è di più. Stiamo usando a!==b!invece di {a}=={b}. Chiaramente, lo stiamo facendo perché è più corto di due byte, ma la domanda interessante è perché funziona. Come ho spiegato sopra, tutti gli operatori sono solo zucchero sintattico per un'espressione con una testa. {a}lo è List[a]. Ma aè una sequenza (come ho detto, un po 'come uno splat in altre lingue), quindi se lo aè 1,-1,1allora otteniamo List[1,-1,1]. Ora postfix !è Factorial. Quindi qui, avremmo Factorial[1,-1,1]. Ma Factorialnon sa cosa fare quando ha un numero di argomenti diverso da uno, quindi questo rimane semplicemente sottovalutato. ==non importa se le cose su entrambi i lati sono elenchi, confronta solo le espressioni e se sono uguali dàTrue(in questo caso, in realtà non darà Falsese non lo sono, ma i pattern non corrispondono se la condizione restituisce qualcosa di diverso True). Ciò significa che il controllo di uguaglianza funziona ancora se ci sono almeno due elementi negli elenchi. E se ce n'è solo uno? Se aè 1allora a!è ancora 1. Se aè -1quindi a!ComplexInfinity. Ora, il confronto 1con se stesso funziona ancora bene, ovviamente. Ma ComplexInfinity == ComplexInfinityrimane non valutato e non dà vero anche se a == -1 == b. Fortunatamente, questo non importa, perché l'unica situazione in cui si presenta è PlusMinus[-1, -1]che non è comunque un OVSF valido! (Se la condizione tornasse True, la chiamata ricorsiva segnalerebbeFalsedopotutto, quindi non importa che il controllo non funzioni.) Non possiamo usare lo stesso trucco per il {a}==-{b}fatto -che non verrebbero sottoposti a thread Factorial, ma solo thread List.

Il pattern matcher si occuperà del resto e troverà semplicemente la definizione corretta da applicare.


9

Haskell, 57 byte

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

Dato l'elenco di input l, cresce un codice OVSF sa partire da [1]e concatenando ripetutamente uno so -s, qualunque sia il primo elemento corrispondente a quello di l. Quindi, controlla che il risultato sia lalla fine. Questo viene verificato una volta che sha lunghezza almeno quella di l.

Alcune strutture ricorsive alternative hanno anche dato 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 / Octave , 94 byte

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

Questo utilizza un nuovo approccio: i codici OVSF di lunghezza consentiti Ncompaiono nella log2(N)-esima matrice Walsh , poiché sono sostanzialmente definiti dalla stessa ricorsione:

Le matrici di Walsh sono casi speciali delle matrici di Hadamard di dimensioni N x Nse ha Nuna potenza di due. (Esistono anche matrici Hadamard di altre dimensioni.) MATLAB e Octave hanno una varietà di funzioni integrate che generano matrici di test per testare le proprietà degli algoritmi numerici, tra cuihadamard() . Fortunatamente per i poteri hadamard()dell'uso di due MATLAB esattamente la costruzione delle matrici gallesi.

Quindi questa funzione controlla prima se la lunghezza degli ingressi è una potenza di due, e se lo è, controlla se è una riga della matrice gallese di dimensioni corrispondenti.

Provalo online!


5

Python, 64 byte

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

Suddivide l'elenco in elementi con indicizzazione pari ed elementi con indicizzazione dispari tramite sezioni. Verifica se i vettori del risultato sono uguali o negativi moltiplicandone uno per il segno forzato dal suo primo elemento. Quindi, esegue lo stesso controllo ricorsivo sugli elementi con indicizzazione pari.

Per il caso base, se il controllo fallisce, rifiuta a meno che l'elenco non lo sia [1] . Anche l'elenco vuoto viene rifiutato in modo specifico per evitare un ciclo infinito.

Una strategia diversa come la mia risposta di Haskell dà 66 byte:

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 byte

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

La funzione ggenera l' niterazione di elenchi (relativamente inefficiente, poiché length $ g n == 3^n, tuttavia, se eliminassimo i duplicati, otterremmo 2^n),f controlla se il nostro elenco è presente in uno di essi. Grazie a @Zgrab per alcuni suggerimenti!

Provalo online!


L'esecuzione degli ultimi 2 casi di test non ha prodotto risultati per me.
Oliver,

@obarakon Sì, è perché gè molto inefficiente e produce una tonnellata di duplicati. (Controlla la sezione debug , probabilmente è a causa dei limiti di tempo o di memoria.)
flawr

2

JavaScript (ES6), 130 93 87 85 83 byte

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))

dimostrazione

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 byte

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

Versione precedente che controllava gli elementi per assicurarsi che fossero 1o -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)

Spiegazione:

  • La lunghezza non può essere zero
  • La lunghezza deve essere una potenza di 2
  • Il primo elemento deve essere 1
  • Gli elementi in posizioni che hanno una potenza di 2 devono essere 1 o -1
  • Gli elementi in altre posizioni sono il prodotto di tutti gli elementi nelle posizioni corrispondenti alla maschera di bit, ad es a[22] == a[2] * a[4] * a[16]. Dal momento che a[20] == a[4] * a[16]è già stato verificato, soloa[22] == a[2] * a[20] deve essere verificato.
  • Il controllo sopra riportato dà risultati degeneri per inon aver impostato almeno due bit. Nel caso di zero bit impostati, controlla quello a[0] == a[0] * a[0], che è falso per a[0] == -1, mentre nel caso di un bit impostato, controlla quello a[i] == a[0] * a[i].

È possibile modificare (l=a.length)&&!(l&l-1)per (l=a.length)&-l==lsalvare 4 byte
Patrick Roberts,

@PatrickRoberts Non è vero l==0?
Neil,

Oh, hai ragione. Bene allora (l=a.length)&&l&-l==l? per salvare 1 byte ...
Patrick Roberts,

In realtà non importa, la tua funzione fallisce per il caso [1,1,1,1,-1,-1,-1,-1,1,1,1,1,1,1,1,1]anche senza i miei suggerimenti.
Patrick Roberts,

@PatrickRoberts l&-l==lnon funziona perché ==ha una precedenza maggiore di &. E il test case non funziona a causa di un refuso che mi costerà un byte da risolvere.
Neil,

2

MATL , 21 20 byte

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

Provalo online! Oppure verifica tutti i casi di test .

Come funziona

Il codice divide l'array in due parti di uguale lunghezza: il primo con le voci con indice dispari, il secondo con le voci con indice pari. I due pezzi sono costretti ad avere la stessa lunghezza, con uno zero di riempimento nel secondo, se necessario. Quindi il codice lo verifica

  1. Le voci corrispondenti dei due pezzi sono tutte uguali o tutte diverse;
  2. Nessuna voce nel secondo pezzo è zero;
  3. La lunghezza dei pezzi supera 1.

Se queste tre condizioni sono soddisfatte, il processo viene nuovamente applicato sul primo pezzo. Se il ciclo viene chiuso perché la lunghezza era già 1, l'input è un codice OFSV. Altrimenti no.

La condizione 1 ripetuta è una versione equivalente della proprietà di definizione dei codici OVSF. Per un array di lunghezza pari a 8, l'approccio semplice sarebbe quello di verificare che le voci 1,2,3,4 siano tutte uguali o tutte diverse rispettivamente dalle voci 5,6,7,8 (questa è la proprietà che definisce). Ma possiamo verificare in modo equivalente che le voci 1,3,5,7 siano tutte uguali o tutte diverse rispetto alle voci 2,4,6,8 rispettivamente; e questo risulta utilizzare meno byte.

La condizione 2 assicura che la lunghezza dell'ingresso sia una potenza di 2: in caso contrario, verrà introdotto uno zero di riempimento in un determinato momento.

`        % 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 byte

Sì, liste infinite!

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

Versioni alternative:

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

Grazie per il (0-)trucco, ero bloccato con negateo((-1)*)
Bergi l'

1

APL, 46 byte

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

Abbastanza semplice:

  • Casi di base:
    • 0::0: se si verifica un errore, restituisce 0
    • ⍵≡,1:1: se l'ingresso è esattamente [1], restituisce 1
    • ⍬≡⍵:0: se l'ingresso è un elenco vuoto, restituisce 0
  • Caso ricorsivo:
    • Z←.5×⍴⍵: Zè la metà della lunghezza dell'input
    • Y←⍵↓⍨Z: Yè l'ultima metà dell'input (questo fallisce se ⍴⍵è irregolare, innescando il gestore delle eccezioni)
    • (∇Y)∨∇-Y: l'ultima metà dell'elenco o la negazione dell'ultima metà dell'elenco devono essere un codice OVSF
    • (∇Z↑⍵)∧: e la prima metà dell'elenco deve essere un codice OVSF.

1
Non credo sia sufficiente verificare la codicità OVSF per la seconda metà; dovrebbe essere uguale alla prima metà o alla sua negazione.
Zgarb,

1
dicono che BASIC è un languore di alto livello e APL è un alto livello di angoscia: ')
cat

dicono che BASIC è un languore di alto livello e APL è un alto livello di angoscia: ')
cat

1

Haskell, 69 68 byte

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

Esempio di utilizzo: g [-1,1]-> False.

Ancora più inefficiente della risposta di @ flawr . Richiede troppo tempo e memoria per 4 elenchi di elementi. Per vedere che l'elenco dei codici OVSF (con molti duplicati) viene effettivamente creato, prova:

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

che ritorna

[[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]]

cioè l'elenco inizia con tutti i 16 elenchi di elementi (4 volte concatenati, a causa di [1..4]), continua con tutti gli 8 elenchi di elementi e così via fino alla fine [1].

Modifica: @xnor ha salvato un byte. Grazie!


Ah, mi ero completamente dimenticato scanr!
flawr

Penso che puoi tagliare un byte facendo any(elem x)invece di elem x$ce non definendo 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)))

Costruisce in modo ricorsivo e controlla ogni elenco fino alla lunghezza dell'elenco di input, a partire da [1].

Il valore di ritorno è JS verità o falsità, in particolare 1o truese valido, 0oppurefalse o undefinedse non valida.

Test

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 byte

(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)))))

Suddivide l'input cin due metà ae bverifica se i loro prodotti elementali sono tutti identici. In tal caso, verifica che la prima metà sia una sequenza valida.

Questo è di 142 byte ma l'ho trovato più interessante:

#((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))))))%)

loopcalcola log_2la lunghezza dell'input, iterategenera sequenze di molte iterazioni basate sulla definizione. Ciò restituisce l'argomento di input se è una sequenza valida e in caso nilcontrario.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.