Prendiamo $ 1,000,000 di Beal


17

Beal's Conjecture ha un premio di un milione di dollari se lo provi / confondi.

Indica che se A ^ x + B ^ y = C ^ zA, B, C, x, y e z sono numeri interi positivi con x, y, z> 2, allora A, B e C hanno un fattore primo comune.

La sfida è scrivere un programma che cerchi un contro esempio per confutare questo!

Regole

  • Scrivi un programma alla ricerca di un contro esempio della congettura di Beal
  • È possibile eseguire una ricerca esaustiva (ovvero tutte le possibili combinazioni di numeri che si adattano a questo modulo) o utilizzare alcune ottimizzazioni (ad esempio, A e B sono simmetriche).
  • È necessario utilizzare numeri interi di precisione arbitraria.

Appunti

  • Questo è un concorso di popolarità, sii creativo!
  • La velocità non è necessaria, ma la rende più interessante. Ottimizzare!
  • Sono anche interessato a vedere anche il codice più corto. Riceverai un +1 da me!
  • Eseguirò il programma vincente su un supercomputer a cui ho accesso!
  • Questa congettura è considerata vera, ma ciò non significa che non possiamo provarci!
  • Anche Peter Norvig di Google ha tentato questo problema. Puoi usare la sua pagina come guida. Ha un breve programma Python che puoi usare come esempio.
  • Qualche altro ragazzo (che lavora anche con Google) ha notevolmente migliorato l'approccio di Norvig, la sua pagina (con codice sorgente) può essere trovata qui .
  • La mia domanda SO relativa a questo di due anni fa può anche essere utile: Fin tutte A ^ x in un dato intervallo .

1
Supercomputer? Adesso va bene. Qualche possibilità di dividere i soldi?
3ıʇǝɥʇuʎs

@Synthetica Questa congettura è già stata testata con numeri molto, molto, molto grandi, quindi questo è principalmente per divertimento. Ma ovviamente possiamo dividere i soldi :)
Austin Henley

2
"Dovrebbe continuare per sempre o consentire un limite superiore finito (non importa quanto grande)." ... al contrario di quali alternative?
undergroundmonorail,

@undergroundmonorail Funziona solo per piccoli numeri.
Austin Henley,

2
I numeri piccoli sono un limite superiore finito.
undergroundmonorail,

Risposte:


4

Sono pateticamente pigro (gioco di parole intenzionale), ma perché no ... sembra soddisfare le regole.

Haskell, 204

import Control.Monad
import Control.Monad.Omega
main=print.filter(\[(a,x),(b,y),(c,z)] 
 ->and$(a^x+b^y==c^z):zipWith(((>1).).gcd)[a,b,c][b,c,a])
 .runOmega$mapM(\_->liftM2(,)(each[1..])$each[3..])"123"

Stampa 1 tutte le combinazioni che soddisfano la proprietà del controesempio. Ho usato il pacchetto control-monad-omega per la diagonalizzazione ℕ 6 ... potrei essere considerato un imbroglione della biblioteca. Ma visto che qualcuno in seguito pubblicherà una risposta APL in cui tutte queste cose sono integrate nella lingua (o no?), Non me ne frega troppo ...

Ovviamente, il programma è troppo lento (stanchezza ingenua e liste collegate come struttura di dati) per essere prevedibili di fornire effettivamente un controesempio, ma Haskell stesso può effettivamente ottenere prestazioni decenti.


1 Poiché stampa le tuple in formato elenco, ovvero su una riga, devi disattivare il buffering del terminale o non vedrai quando arriva un risultato. In alternativa, puoi sostituirlo printcon in mapM_ printmodo da ottenere una nuova riga dopo ogni risultato, svuotare un terminale con buffer di linea.

Per testare il programma, each[3..]passa a each[2..], quindi otterrai semplicemente tutte le tuple pitagoriche non coprime come risultato.


2

C #, nessun loop

OK, ho scremato un paio di quei collegamenti, ma ad essere sinceri erano un po 'noiosi. Non mi interessa ottimizzare l'inferno con le tabelle hash e quant'altro. Perché dovrei aver bisogno? Hai un dannato supercomputer!

Diavolo, non voglio nemmeno preoccuparmi dei loop! Questa soluzione seguirà la regola no-loop .

Si noti che il codice che sto per scrivere non è un buon codice, o il tipo di codice che scriverei nella vita reale (nel caso in cui qualche potenziale datore di lavoro capisca di leggerlo). Questo codice enfatizza la brevità e la capacità di lavorare in una narrazione, e sottolinea le convenzioni e i rituali, i cicli e così via appropriati.

Per dimostrare di cosa sto parlando, inizieremo con una classe scioccante con campi pubblici per memorizzare gli operandi dell'equazione:

class BealOperands
{
    public BigInteger A, B, C, x, y, z;
}

OK, inizieremo con quella che è probabilmente la sfida più difficile. Dobbiamo trovare un modo per permutare attraverso ogni combinazione di quegli operandi. Ci sono indubbiamente modi per farlo in modo più efficiente che controllare ogni permutazione, ma non riesco a disturbarmi a capirle. E perché dovrei? Abbiamo un dannato supercomputer!

Ecco l'algoritmo che ho ideato. È incredibilmente inefficiente e ripete continuamente gli stessi operandi, ma a chi importa? Supercomputer!

  • Tratta i sei operandi come un numero di base 2 e permuta attraverso ogni combinazione.
  • Tratta i sei operandi come un numero di base 3 e permuta attraverso ogni combinazione.
  • Tratta i sei operandi come un numero di base 4 e permuta attraverso ogni combinazione.
  • (...)

Come fare tutto questo senza loop? Facile! Basta implementare un IEnumerablee associato IEnumeratorper pompare le permutazioni. Più tardi, useremo LINQ per interrogarlo.

class BealOperandGenerator : IEnumerable<BealOperands>
{
    // Implementation of IEnumerable<> and IEnumerable -- basically boilerplate to get to BealOperandGeneratorEnumerator.
    public IEnumerator<BealOperands> GetEnumerator() { return new BealOperandGeneratorEnumerator(); }
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }
}

class BealOperandGeneratorEnumerator : IEnumerator<BealOperands>
{
    public BealOperandGeneratorEnumerator() { Reset(); }

    private BealOperands operands;
    private BigInteger @base;

    public void Reset()
    {
        // A is set to 0, which is "before" its minimum value, because IEnumerators are supposed to
        // point to their first element *after* the first call to MoveNext().
        // All other operands are set to their minimum values.
        operands = new BealOperands { A = 0, B = 1, C = 1, x = 3, y = 3, z = 3 };
        @base = 2;
    }

    public BealOperands Current
    {
        get 
        {
            // We need to return a copy, since we'll be manipulating our internal one.
            return new BealOperands { 
                A = operands.A, B = operands.B, C = operands.C, 
                x = operands.x, y = operands.y, z = operands.z };
        }
    }

    public bool MoveNext()
    {
        // Increment the lowest "digit" and "carry" as necessary.
        operands.A++;
        if (operands.A - 1 >= @base)
        {
            operands.A = 1; operands.B++;
            if (operands.B - 1 >= @base)
            {
                operands.B = 1; operands.C++;
                if (operands.C - 1 >= @base)
                {
                    operands.C = 1; operands.x++;
                    if (operands.x - 3 >= @base)
                    {
                        operands.x = 3; operands.y++;
                        if (operands.y - 3 >= @base)
                        {
                            operands.y = 3; operands.z++;
                            if (operands.z - 3 >= @base)
                            {
                                operands.z = 3; @base++;
                            }
                        }
                    }
                }
            }
        }
        // There will always be more elements in this sequence.
        return true;
    }

    // More boilerplate
    object System.Collections.IEnumerator.Current { get { return Current; } }
    public void Dispose() { }
}

Ora siamo in affari! Tutto ciò che dobbiamo fare è elencare un'istanza di BealOperandGeneratore trovare un controesempio della congettura di Beal.

Il nostro prossimo grosso problema è che non sembra esserci un modo integrato per aumentare BigIntegerla potenza di a BigInteger. C'è BigInteger.Pow(BigInteger value, int exponent), e BigInteger.ModPow(BigInteger value, BigInteger exponent, BigInteger modulus), ma nessun metodo per elevare a BigInteger, alla potenza di un altro BigInteger, modulo infinito.

Che chiodo brillante di un problema! Sembra che sia stato creato per essere risolto con il nostro IEnumerable/ IEnumeratorhammer!

class BigIntegerPowerEnumerable : IEnumerable<Tuple<BigInteger, BigInteger>>
{
    public BigIntegerPowerEnumerable(BigInteger @base, BigInteger exponent) { this.@base = @base; this.exponent = exponent; } 
    BigInteger @base, exponent;

    public IEnumerator<Tuple<BigInteger, BigInteger>> GetEnumerator() { return new BigIntegerPowerEnumerator(@base, exponent); }
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }
}

class BigIntegerPowerEnumerator : IEnumerator<Tuple<BigInteger, BigInteger>>
{
    public BigIntegerPowerEnumerator(BigInteger @base, BigInteger exponent) 
    {
        originalBase = @base; 
        originalExponent = exponent;
        Reset(); 
    }

    BigInteger originalBase, currentBase, originalExponent, currentExponent;
    bool finished;

    public void Reset()
    {
        // IEnumerable.Reset() is a silly method. You're required to implement it when you implement IEnumerable,
        // but it isn't used by foreach or LINQ or anything. If you want to re-enumerate the enumerable, just get
        // a brand new enumerator.
        // In this case it gets in the way. The only reason I'm storing the original values is so I can implement 
        // this useless method properly. I supposed I could just throw a NotImplementedException or something, 
        // but it's done now.
        currentBase = originalBase;
        currentExponent = originalExponent;
        finished = false;
    }

    public bool MoveNext()
    {
        if (finished) return false;

        if (currentExponent <= Int32.MaxValue)
        {
            currentBase = BigInteger.Pow(currentBase, (Int32)currentExponent);
            currentExponent = 1;
            finished = true;
        }
        else
        {
            currentBase = BigInteger.Pow(currentBase, Int32.MaxValue);
            currentExponent -= Int32.MaxValue;
        }
        return true;
    }

    public Tuple<BigInteger, BigInteger> Current
    {
        get { return new Tuple<BigInteger, BigInteger>(currentBase, currentExponent); }
    }

    object System.Collections.IEnumerator.Current { get { return Current; } }
    public void Dispose() { }
}

static class BigIntegerPowExtension
{
    public static BigInteger Pow(this BigInteger @base, BigInteger exponent)
    {
        return new BigIntegerPowerEnumerable(@base, exponent).Last().Item1;
    }
}

Ora abbiamo un metodo di estensione Pow, che può essere chiamato su a BigInteger, e richiede un BigIntegeresponente e nessun modulo.

OK, facciamo un passo indietro. Come possiamo sapere se un particolare BealOperandsè un controesempio della congettura di Beal? Bene, due cose devono essere vere:

  • Gli operandi, quando inseriti in quella formula nella parte superiore della pagina, devono formare una vera equazione.
  • A, B e C NON devono avere un fattore primo comune (ovvero il loro GCD è 1).

Abbiamo ciò di cui abbiamo bisogno per verificare la prima condizione. E risulta che la seconda condizione è molto più facile da controllare di quanto sembri. BigIntegerfornisce un GreatestCommonDivisormetodo adorabile , che ci consente di eludere convenientemente l'intero incubo del tentativo di implementarlo senza loop.

Quindi siamo pronti a scrivere un metodo per verificare se a BealOperandsè un controesempio. Ecco qui...

static class BealOperandsExtensions
{
    public static bool IsBealsConjectureCounterExample(this BealOperands o)
    {
        // If the equation isn't even true, we don't have a counter example unfortunately
        if (o.A.Pow(o.x) + o.B.Pow(o.y) != o.C.Pow(o.z))
        {
            return false;
        }

        // We have a counterexample if A, B and C are coprime
        return BigInteger.GreatestCommonDivisor(o.A, o.B) == 1 &&
               BigInteger.GreatestCommonDivisor(o.A, o.C) == 1 &&
               BigInteger.GreatestCommonDivisor(o.B, o.C) == 1;
    }
}

E finalmente possiamo mettere tutto insieme con questo Mainmetodo piuttosto fluido :

static class Program
{
    static void Main()
    {
        var bealOperandGenerator = new BealOperandGenerator();
        if (bealOperandGenerator.Any(o => o.IsBealsConjectureCounterExample()))
        {
            Console.WriteLine("IN YOUR FACE, BEAL!");
        }
    }
}

2

Non ci sono controesempi con C ^ Z <= 1.0E27.

Da febbraio 2019 sto verificando in C ^ Z <= 1.0E29 supponendo che l'esponente “X” e / o “Y” debba essere> = 5.

La versione corrente di questo programma (“X” e / o “Y”> = 5) impiega meno di 1 secondo su un AMD 2920X per trovare tutte le soluzioni su C ^ Z <= 1.0E15. (Ma tutto il gcd (A, B, C) sono> = 2)

Dettagli su http://www.durangobill.com/BealsConjecture.html

Posso modificare il codice corrente (utilizza "C" e OpenMP) oltre questi limiti, ma per eseguirlo sono necessari più di 128 GB di RAM. (Anche centinaia di CPU aiuterebbero. Migliaia di CPU sarebbero ancora meglio.) (Se hai libero accesso a qualcosa del genere, per favore contattami.)

Il mio indirizzo e-mail è nella mia home page all'indirizzo http://www.durangobill.com


1
Se riesci ad approfondire questo con un po 'di codice, questa potrebbe essere una risposta valida, altrimenti è probabilmente più adatta come commento alla domanda. Tuttavia, in entrambi i casi il lavoro svolto su questo è impressionante.
Οuroso

Molte università hanno cluster ad alte prestazioni. Se ne hai contattato uno, potrebbero essere in grado di concederti l'accesso. Ho visto troppi gruppi solo al minimo!
Austin Henley,

1

La seconda variante del programma di ricerca di Beal è terminata. I risultati sono:

CZ<1026UNX+BY=CZ(X,Y)> =4

2) Se supponi che almeno degli esponenti (X,Y)> =5CZ<1028UNX+BY=CZ(X,Y)> =5

Dettagli su: http://www.durangobill.com/BealsConjecture.html

Le prossime due domande sono: 1) Un supercomputer può estendere la ricerca? 2) Se un supercomputer potesse estendere la ricerca, sarebbe pratico?

1) Per estendere una delle ricerche precedenti a 1.0E30, sarebbero necessari 300 GB di RAM per core, a meno che i core non possano condividere i 300 GB. Per ogni ulteriore ulteriore incremento incrementale della potenza esponenziale oltre 1.0E30, la quantità di RAM richiesta aumenta di un fattore di almeno 2,2.

2) La quantità di potenza di elaborazione necessaria per ogni ulteriore aumento incrementale dell'esponente ae oltre 1,0E30 moltiplica il tempo combinato della CPU di circa 3,8. La ricerca su 1.0E29 ha richiesto 2 settimane usando 12 core. Il tempo del supercomputer non è generalmente "libero", e ci sono pochissime prospettive che ci siano controesempi.

Come guida all'efficienza del codice su durangobill.com/BealE29code.txt, ciascuno dei 12 core ha una media di 220 milioni di iterazioni al secondo per il loop interno. (La media è per la corsa di 2 settimane.) (Un aumento della memoria RAM oltre quello che ho aumenterebbe questa velocità media fino a un fattore 2).

Lascerò che Austin risponda 1) e 2) poiché ha accesso a un supercomputer e io no. (Se per qualche remota possibilità che sia 1) sia 2) siano un "go", posso fornire il codice "C" con il caveat che non ho familiarità con le istruzioni multi-thread per grandi cluster di supercomputer.)


Potete per favore usare solo una risposta alla domanda, piuttosto che dividerla a tre? Sai che puoi modificare le tue risposte precedenti, giusto?
Jo King,

Apprezzo che tu trovi un controesempio e poi non lo stampi ... Anche questo non è molto da golf ...
Axman6

0

Ho dovuto inserire questo in 2 commenti per adattarlo.

Le matrici principali sono allocate come segue:

SortHeads = calloc(PRIME1+1, 8);
X2YmodPrime1 = calloc(ARRAYSIZE+1, 4);
X2YmodPrime2 = calloc(ARRAYSIZE+1, 4);
Base = calloc(ARRAYSIZE+1, 4);
Power = malloc(ARRAYSIZE+1);

(Avrai bisogno di 128 GB di RAM per questi array)

con:

#define PRIME1 2147483647LLU
#define PRIME2 2147483629LLU
#define ARRAYSIZE 4700000000LL

"Base" in realtà ha bisogno di 33 bit ( cbrt(1.0E29)) - il bit extra è inserito in "Potenza" (che richiede solo 7 bit.)

Le matrici funzionano in modo simile a una tabella hash. Tuttavia, poiché sono ordinati in base a PRIME1 e utilizzati solo come tabelle di ricerca, non è necessario che gli elenchi collegati vi accedano. Il risultato è quindi una ricerca del tempo lineare molto veloce per vedere se una prova A ^ X + B ^ Y = qualsiasi C ^ Z.

Quindi le affermazioni nel ciclo più interno sono profonde solo due anelli.

Le istruzioni "Pragma" controllano il numero di core multielaborazione utilizzati (in questo caso 12): tutti possono accedere alla singola copia degli array.

Ecco il codice "principale" (in "C") (spero che i commenti si adattino alla lunghezza della riga pubblicata. In caso contrario, copiarli e incollare il codice in alcuni documenti che hanno una lunghezza della riga più lunga.)


La casella dei commenti mi consentirà di utilizzare solo 600 caratteri e ho bisogno di oltre 3000 caratteri per il codice. (Qualche suggerimento?) (Posso pubblicare il codice sulla mia pagina web se non riesco a pubblicarlo qui.)
Bill Butler

Ho inserito qui il codice "C" principale. durangobill.com/BealE29code.txt Se non altro, è un esempio di "come farlo" per l'elaborazione di thread multipli in "C".
Bill Butler,

1
Benvenuti nel sito. Mentre le caselle di commento sono limitate a 600 caratteri, la tua risposta non lo è. Dovresti essere in grado di adattare facilmente il tuo codice alla tua risposta. Se non stai provando a tagliare i commenti. Inoltre ho riformattato la tua risposta per utilizzare i blocchi di codice. Questi possono essere fatti con 4 spazi come ho fatto io. Quando sposti il ​​tuo codice nella risposta, dovresti inserirlo in un blocco di codice o sarà del tutto illeggibile.
Post Rock Garf Hunter,
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.