Sequenza di fumo frattale


33

introduzione

A229037 ha una trama abbastanza intrigante (almeno per i primi termini):

C'è la congettura che potrebbe effettivamente avere una sorta di proprietà frattale.

Come viene costruita questa sequenza?

Definire a(1) = 1, a(2) = 1poi per ciascuna n>2trovare un positivo minimo numero intero a(n)tale che per ogni sequenza aritmetica 3 termine n,n+k,n+2kdi indici, i valori corrispondenti della sequenza a(n),a(n+k),a(n+2k)è non una successione aritmetica.

Sfida

Dato un numero intero positivo ncome input, genera i primi ntermini a(1), ... , a(n)di questa sequenza. (Con qualsiasi formattazione ragionevole. Possibili caratteri / stringhe iniziali / di addestramento sono irrilevanti.)

Sono disponibili frammenti per generare questa sequenza, ma penso che altri approcci potrebbero essere più giocabili a golf / più adatti a determinate lingue.

Fateci sapere come funziona il vostro programma. Se incrocia un algoritmo particolarmente efficiente, potresti anche menzionarlo, poiché consentirebbe di tracciare più termini della sequenza in tempi più brevi.

Primi casi di test:

1, 1, 2, 1, 1, 2, 2, 4, 4, 1, 1, 2, 1, 1, 2, 2, 4, 4, 2, 4, 4, 5, 5, 8, 5, 5, 9, 1, 1, 2, 1, 1, 2, 2, 4, 4, 1, 1, 2, 1, 1, 2, 2, 4, 4, 2, 4, 4, 5, 5, 8, 5, 5, 9, 9, 4, 4, 5, 5, 10, 5, 5, 10, 2, 10, 13, 11, 10, 8, 11, 13, 10, 12, 10, 10, 12, 10, 11, 14, 20, 13

Altre prove:

  a(100)  =   4
  a(500)  =   5
 a(1000)  =  55
 a(5000)  =  15
a(10000)  = 585

Tutti i termini fino a n=100000sono disponibili qui: https://oeis.org/A229037/b229037.txt

Grazie @ MartinBüttner per l'aiuto e l'incoraggiamento.


2
Ehi, dove ho visto questo grafico prima? MrGreen
Luis Mendo il

12
Sposta leggermente la testa a sinistra, ingrandisci un po ', eccoti! (:
flawr

4
Un video numerico appena spuntato: youtube.com/watch?v=o8c4uYnnNnc
flawr

2
Scommetto che il suo codice non è così matto!
Luis Mendo,

Risposte:


12

Python 2, 95 byte

l=[];n=input()
exec"a=min(set(range(n))-{2*b-c for b,c in zip(l,l[1::2])});print-~a;l=[a]+l;"*n

Il trucco principale è nel generare i numeri che il nuovo valore deve evitare. Mantenendo la sequenza inversa finora l, diamo un'occhiata a quali elementi potrebbero formare una progressione aritmetica a tre termini con il valore che stiamo per aggiungere.

? 4 2 2 1 1 2 1 1   a b c
^ ^ ^               ? 4 2
^   ^   ^           ? 2 1
^     ^     ^       ? 2 2
^       ^       ^   ? 1 1

Gli altri numeri sono i membri associati di le ogni secondo elemento di l, quindi zip(l,l[1::2]). Se questa coppia è (b,c)allora (a,b,c)accade la progressione aritmetica a=2*b-c. Dopo aver generato il set di a's da evitare, il codice prende il minimo del complemento, lo stampa e lo antepone all'elenco. (In realtà, il calcolo viene eseguito con numeri diminuiti di 1 e stampati 1 in più, per range(n)servire come un universo di candidati.)


8

Mathematica, 95 byte

For[n_~s~k_=0;n=0,n<#,For[i=n,--i>0,s[2n-i,2f@n-f@i]=1];For[++n;i=1,n~s~i>0,++i];Print[f@n=i]]&

Certamente non è l'approccio più golfistico, ma in realtà è abbastanza efficiente, rispetto agli algoritmi che ho provato dalla pagina OEIS.

Al contrario di controllare tutti i valori proibiti per ogni s (n) quando ci arriviamo sto usando un approccio basato sul setaccio. Quando troviamo un nuovo valore s (n) controlliamo immediatamente quali valori ciò proibisce per m> n . Quindi risolviamo semplicemente la s (n + 1) cercando il primo valore che non era proibito.

Questo può essere reso ancora più efficiente modificando il condizionale --i>0in 2n-#<=--i>0. In tal caso, evitiamo di controllare i valori proibiti per n maggiore dell'input.

Per una versione un po 'più leggibile, ho iniziato con questo codice, che memorizza i risultati fino a maxin una funzione f, e poi l' ho portato alla funzione pura di una riga sopra:

 max = 1000;
 ClearAll[sieve, f];
 sieve[n_, k_] = False;
 For[n = 0, n < max,
  temp = f[n];
  For[i = n - 1, i > 0 && 2 n - i <= max, --i,
   sieve[2 n - i, 2 temp - f[i]] = True;
   ];
  ++n;
  i = 1;
  While[sieve[n, i], ++i];
  f@n = i;
  ]

3

Haskell, 90 , 89 , 84 , 83 byte

Probabilmente si può giocare a golf di più, ma questo è ancora un primo tentativo decente :

a n|n<1=0|n<3=1|1<2=[x|x<-[1..],and[x/=2*a(n-k)-a(n-k-k)||a(n-k-k)<1|k<-[1..n]]]!!0

Ungolfed:

a n | n<1        = 0 
    | n<3        = 1
    | otherwise  = head (goods n)

goods n = [x | x <- [1..], isGood x n]

isGood x n = and [ x - a(n-k) /= a(n-k) - a(n-k-k) || a(n-k-k) == 0 | k <- [1..n] ]

Questa è una semplice implementazione che restituisce '0' per fuori limite. Quindi, per ogni possibile valore, verifica che per tutti k <= n e nei limiti, [x, a (xk), a (x-2k)] non sia una sequenza aritmetica.

Limite superiore sulla complessità temporale (utilizzando il fatto dalla pagina OEIS che a (n) <= (n + 1) / 2:

t n <= sum[ sum[2*t(n-k) + 2*t(n-k-k) | k <- [1..n]] | x <- [1..(n+1)/2]]
    <= sum[ sum[4*t(n-1)              | k <- [1..n]] | x <- [1..(n+1)/2]]
    <= sum[     4*t(n-1)*n                         ] | x <- [1..(n+1)/2]]
    <=          4*t(n-1)*n*(n+1)/2
    ->
O(t(n)) == O(2^(n-2) * n! * (n+1)!)

Non sono sicuro di quanto sia buono questo limite perché il calcolo dei primi valori 1k di 't' e l'utilizzo di un modello lineare sui registri dei valori hanno dato appx. O (22 ^ n), con valore p <10 ^ (- 1291), nel caso in cui sia importante.

A livello di implementazione, compilando con '-O2', sono stati necessari ~ 35 minuti per calcolare i primi 20 valori.


1
Qual è la complessità temporale del tuo programma?
flawr

@flawr Aggiunta al post alcune analisi di complessità temporale
Michael Klein,

3

Brachylog , 33 31 byte

;Ė{~b.hℕ₁≜∧.¬{ġh₃hᵐs₂ᶠ-ᵐ=}∧}ⁱ⁽↔

Provalo online!

Nel caso sia importante: il golf a 2 byte era possibile grazie a una funzione che avevo richiesto dopo aver lavorato su questa sfida.

Spiegazione

Generiamo iterativamente la sequenza come un elenco in ordine inverso, ad esempio [2,2,1,1,2,1,1], e invertiamo alla fine.

Ci sono un paio di predicati nidificati qui. Diamo un'occhiata da dentro e fuori. Il primo ġh₃hᵐs₂ᶠ-ᵐ=, prende una candidatura secondaria a(n),a(n-1),...,a(0)e determina se a(n),a(n-k),a(n-2k)per alcuni è una sequenza aritmetica k.

ġ            Group the list into equal-length sublists (with the possible exception of
             the last sublist, which might be shorter)
 h₃          Get the first 3 sublists from that list
   hᵐ        and get the head of each of those 3 sublists
             We now have a list containing a(n),a(n-k),a(n-2k) for some k
     s₂ᶠ     Find all 2-element sublists of that list: [a(n),a(n-k)] and [a(n-k),a(n-2k)]
        -ᵐ   Find the difference of each pair
          =  Assert that the two pairwise differences are equal

Ad esempio, con input di [1,2,1,1,2,1,1]:

ġ has possible outputs of
    [[1],[2],[1],[1],[2],[1],[1]]
    [[1,2],[1,1],[2,1],[1]]
    [[1,2,1],[1,2,1],[1]]
    [[1,2,1,1],[2,1,1]]
    [[1,2,1,1,2],[1,1]]
    [[1,2,1,1,2,1],[1]]
    [[1,2,1,1,2,1,1]]
h₃ has possible outputs of
    [[1],[2],[1]]
    [[1,2],[1,1],[2,1]]
    [[1,2,1],[1,2,1],[1]]
hᵐ has possible outputs of
    [1,2,1]
    [1,1,2]
    [1,1,1]
s₂ᶠ has possible outputs of
    [[1,2],[2,1]]
    [[1,1],[1,2]]
    [[1,1],[1,1]]
-ᵐ has possible outputs of
    [-1,1]
    [0,-1]
    [0,0]
= is satisfied by the last of these, so the predicate succeeds.

Il predicato successivo verso l'esterno, ~b.hℕ₁≜∧.¬{...}∧inserisce una sottosequenza a(n-1),a(n-2),...,a(0)e produce la sottosequenza successiva più grande a(n),a(n-1),a(n-2),...,a(0).

~b.hℕ₁≜∧.¬{...}∧
~b.                 The input is the result of beheading the output; i.e., the output is
                    the input with some value prepended
  .h                The head of the output
    ℕ₁              is a natural number >= 1
      ≜             Force a choice as to which number (I'm not sure why this is necessary,
                    but the code doesn't work without it)
        ∧           Also,
         .          the output
          ¬{...}    does not satisfy the nested predicate (see above)
                    I.e. there is no k such that a(n),a(n-k),a(n-2k) is an arithmetic sequence
                ∧   Break unification with the output

Infine, il predicato principale ;Ė{...}ⁱ⁽↔accetta un numero di input e genera molti termini della sequenza.

;Ė{...}ⁱ⁽↔
;           Pair the input number with
 Ė          the empty list
  {...}ⁱ⁽   Using the first element of the pair as the iteration count and the second
            element as the initial value, iterate the nested predicate (see above)
         ↔  Reverse, putting the sequence in the proper order

3

Rubino , 71 byte

->n,*a{a.fill(0,n){|s|([*1..n]-(1..s/2).map{|o|2*a[s-o]-a[s-2*o]})[0]}}

Provalo online!

Genera tutti i valori proibiti, quindi accetta il complemento di quell'array in (1..n) e accetta il primo valore del risultato. Ciò significa che sto assumendo che a[n] <= nper tutto n, che è facilmente dimostrato usando l'induzione (se i primi termini n / 2 sono tutti inferiori a n / 2, allora non può esserci una progressione aritmetica che porta a n).

Anche qui il trucco sintattico è leggermente interessante: *aviene utilizzato per inizializzare un array di argomenti aggiuntivi (che verrebbero ignorati se ne passassimo uno qualsiasi), quindi a.fillmuta l'array di argomenti e lo restituisce implicitamente.


1
-1 byte: anziché a[s-o]e a[s-2*o], è possibile utilizzare a[s-=1]ea[s-o]
GB

3

APL (Dyalog Extended) , SBCS 37 byte

Mille grazie ad Adám per il suo aiuto nello scrivere e giocare a golf questa risposta in The APL Orchard , un ottimo posto per imparare la lingua APL. Provalo online!

Modifica: -6 byte grazie ad Adám

⌽{⍵,⍨⊃(⍳1+≢⍵)~-¯2⊥⍵[2×⍀⍥⍳⌊2÷⍨≢⍵]}⍣⎕,⍬

Spiegazione

{⍵,⍨⊃(⍳1+≢⍵)~-¯2⊥⍵[2×⍀⍥⍳⌊2÷⍨≢⍵]}   is our right argument, the sequence S

                        2÷⍨≢⍵    We start by calculating X = len(S2
                                 Get a range [1, X]
                   2×⍀⍥           With that we can get S[:X] and S[:X×2:2]
                                  or S up to halfway and every 2nd element of S
             2⊥⍵[           ]   And with that we can get 2*S[:X] - S[:X×2:2]
                                  Which is C=2*B-A of a progression A B C
     (⍳1+≢⍵)~                     We remove these Cs from our possible a(n)s
                                  I use range [1, len(S)+1]
                                 Get the first result, which is the minimum
 ⍵,⍨                              And then prepend that to S


⌽{...}⍣⎕,⍬

 {...}⍣⎕    We iterate an "input"  times
        ,⍬  with an empty list  as the initial S
           and reversing S at the end as we have built it backwards

APL (Dyalog Unicode) , 43 39 38 byte SBCS

Ecco una soluzione più veloce ma meno golfy che può calcolare ⍺(10000)in pochi secondi.

⌽{⍵,⍨⊃(⍳1+≢⍵)~-⌿⍵[1 2 1∘.×⍳⌊2÷⍨≢⍵]}⍣⎕,⍬

Provalo online!


2

MATLAB, 156 147 byte

Alla fine ho iniziato a giocare a golf un po ':

N=input('');s=[0;0];for n=1:N,x=s(n,~~s(n,:));try,a(n)=find(~ismember(1:max(x)+1,x),1);catch,a(n)=1;end,s(n+1:2*n-1,end+1)=2*a(n)-a(n-1:-1:1);end,a

Ungolfed:

N=input('');                                   % read N from stdin

s=[0;0];
for n=1:N,
    x=s(n,~~s(n,:));                           % x=nonzeros(s(n,:));
    try,
        a(n)=find(~ismember(1:max(x)+1,x),1);  % smallest OK number
    catch,
        a(n)=1;                                % case of blank page for n
    end,

    s(n+1:2*n-1,end+1)=2*a(n)-a(n-1:-1:1);     % determined new forbidden values
end,
a                                              % print ans=...

L'input viene letto da STDIN e la stampa viene eseguita automaticamente con ans=e cose aggiunte. Spero che questo si qualifichi come output "ragionevole".

Questa è una soluzione basata vaglio: la variabile s(i,:)tiene traccia di quei valori di sequenza che sono proibiti per a(i). Il try-catchblocco è necessario per trattare il caso di una smatrice vuota (che significa zero completo) : in questo caso 1è già consentito il valore più basso di .

Tuttavia, la necessità di memoria (o runtime?) Diventa piuttosto disordinata sopra N=2000. Quindi ecco una soluzione non competitiva, più efficiente:

%pre-alloc
s = zeros([N,fix(N*0.07+20)]); %strict upper bound, needs adjusting later
i = zeros(1,N);

a = 1;
for n = 2:N,
    x = s(n,1:i(n));
    if isempty(x),
        a(n) = 1;
    else
        a(n) = find(~ismember(1:max(x)+1,x),1);
    end,

    j = n+1:min(2*n-1,N);
    i(j) = i(j)+1;
    s(N,max(i(j))) = 0;   %adjust matrix size if necessary
    b = a(n-1:-1:1);
    s(sub2ind([N,size(s,2)+1],j,i(j))) = 2*a(n)-b(1:length(j));
end

In questa implementazione la smatrice contiene ancora valori proibiti, ma in modo ben ordinato, senza blocchi zero (che sono presenti nella versione concorrente). Il vettore indice itiene traccia del numero di vettori proibiti in s. A prima vista le celle sarebbero perfette per tenere traccia delle informazioni archiviate s, ma sarebbero lente e non potremmo indicizzarne una parte contemporaneamente.

Una brutta caratteristica di MATLAB è che mentre puoi dire M(1,end+1)=3;ed espandere automaticamente una matrice, non puoi fare lo stesso con l'indicizzazione lineare. In un certo senso ha senso (come dovrebbe MATLAB conoscere la dimensione della matrice risultante, nel quadro della quale dovrebbe interpretare gli indici lineari?), Ma mi ha comunque sorpreso. Questo è il motivo della linea superflua s(N,max(i(j))) = 0;: questo espanderà la smatrice per noi ogni volta che sarà necessario. L'ipotesi della dimensione iniziale N*0.07+20deriva da un adattamento lineare ai primi pochi elementi, comunque.

Per testare il runtime, ho anche controllato una versione leggermente modificata del codice, in cui ho inizializzato la smatrice per avere dimensioni N/2. Per i primi 1e5elementi questa sembra essere un'ipotesi molto generosa, quindi ho rimosso la fase di espansione smenzionata nel paragrafo precedente. Questi insieme implicano che il codice sarà più veloce, ma anche meno robusto ad altissimo N(dal momento che non so come appare la serie lì).

Quindi, ecco alcuni runtime, a confronto

  • v1: la versione giocata a golf,
  • v2: la versione di dimensioni ridotte, a prova di errore e
  • v3: la generosa dimensione iniziale, potrebbe fallire per la versione N di grandi dimensioni.

Li ho misurati su R2012b, prendendo il meglio di 5 corse all'interno di una definizione di funzione denominata con tic/toc.

  1. N=100:
    • v1: 0.011342 s
    • v2: 0.015218 s
    • v3: 0.015076 s
  2. N=500:
    • v1: 0.101647 s
    • v2: 0.085277 s
    • v3: 0.081606 s
  3. N=1000:
    • v1: 0.641910 s
    • v2: 0.187911 s
    • v3: 0.183565 s
  4. N=2000:
    • v1: 5.010327 s
    • v2: 0.452892 s
    • v3: 0.430547 s
  5. N=5000:
    • v1: N / A (non ha aspettato)
    • v2: 2.021213 s
    • v3: 1.572958 s
  6. N=10000:
    • v1: N / A
    • v2: 6.248483 s
    • v3: 5.812838 s

Sembrerebbe che la v3versione sia significativamente, ma non incredibilmente più veloce. Non so se un elemento di incertezza (per molto grande N) valga il minore aumento del tempo di esecuzione.


M=1;M(end+1)=2;funziona perfettamente bene per me?
flawr

@flawr che funzionerà per scalari e vettori. Prova M=rand(2); M(end+1)=2invece :)
Andras Deak il

Ah ora vedo =)
flawr

2

Gelatina , 24 19 byte

Questa è la mia prima risposta di Jelly da un po 'di tempo. Sono contento di essere tornato.

Questa è una porta della mia risposta APL che di per sé è un adattamento di molti degli algoritmi usati qui. La differenza principale è che questo è indicizzato 0.

Modifica: -5 byte grazie a Jonathan Allan.

Provalo online!

Ḋm2ɓṁḤ_
ŻJḟÇṂ;
1Ç¡U

Spiegazione

Ḋm2ɓṁḤ_  First link. Takes our current sequence S as our left argument.

         We are trying to calculate, of an arithmetic progression A B C, 
           the C using the formula, C = 2*B - A
Ḋ        Remove the first element of S.
 m2      Get every element at indices 0, 2, 4, ...
           This is equivalent to getting every second element of S, a list of As.
   ɓ     Starts a dyad with reversed arguments.
           The arguments here are S and As.
    ṁ    This molds S in the shape of As, giving us a list of Bs.
     Ḥ   We double the Bs.
      _  And subtract As from 2 * Bs.

ŻJḟÇṂ;  Second link. Takes S as our left argument.

Ż       Append a 0 to S.
 J      Range [1, len(z)]. This gets range [1, len(S) + 1].
  ḟÇ    Filter out the results of the previous link, our Cs.
    Ṃ   Take the minimum of Cs.
     ;  And concatenate it with the rest of the sequence so far.

1Ç¡U  Third link. Where we feed our input, n.

1     A list with the element 1.
 Ç¡   Run the previous link n times.
   U  Reverse everything at the end.

farà altrettanto bene come œ-salvare un byte
Jonathan Allan il

Abbastanza sicuro che puoi azzerare l'indice (come da sequenza ) e quindi sostituire “”con l' 1output di una rappresentazione Jelly di un elenco da un programma completo, salvandone uno in più.
Jonathan Allan,

Œœị@2può essere golfato per Ḋm2salvare due.
Jonathan Allan,

L‘Rpuò essere golfato per ŻJsalvarne uno.
Jonathan Allan,

@JonathanAllan Cinque interi byte! Grazie!
Sherlock9

1

ES6, 114 byte

n=>[...r=Array(n)].map((x,i,s)=>{for(y=1;x&&x[y];y++);r[i]=y;for(j=i;++j<n;s[j][y+y-r[i+i-j]]=1)s[j]=s[j]||[]}&&r

Restituisce una matrice dei primi n elementi della sequenza, quindi gli indici sono 1 rispetto alla versione non modificata in basso. Ho usato l'approccio setaccio. Questa versione rallenta dopo circa n = 2000; una versione precedente evitava di leggere l'inizio dell'array, il che significava che non rallentava fino a circa n = 2500. Una versione precedente utilizzava l'array setaccio come un elenco di valori proibiti anziché come un array booleano di cui erano vietati i valori; questo potrebbe arrivare a circa n = 5000 senza rompere il sudore. La mia versione originale ha cercato di utilizzare maschere di bit, ma si è rivelato inutile (ed era anche troppo lungo a 198 byte).

La versione non così lenta non convertita:

function smoke(n) {
    result = [];
    sieve = [];
    for (i = 1; i <= n; i++) {
        value = 1;
        if (sieve[i]) {
            while (sieve[i][value]) {
                value++;
            }
        }
        result[i] = value;
        for (j = 1; j < i && i + j <= n; j++) {
            if (!sieve[i + j]) sieve[i + j] = [];
            sieve[i + j][value + value - result[i - j]] = true;
        }
    }
    return result;
}
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.