Давайте возьмем Била в 1 000 000 долларов


17

Гипотеза Била имеет приз в миллион долларов, если вы докажете / опровергнете его.

В нем говорится, что если A ^ x + B ^ y = C ^ zA, B, C, x, y и z являются натуральными числами с x, y, z> 2, то A, B и C имеют общий простой множитель.

Задача состоит в том, чтобы написать программу, которая ищет контрпример, чтобы опровергнуть это!

правила

  • Напишите программу, которая ищет контр-пример гипотезы Била
  • Вы можете выполнить исчерпывающий поиск (т. Е. Все возможные комбинации чисел, которые соответствуют этой форме) или использовать некоторые оптимизации (например, A и B симметричны).
  • Вы должны использовать целые числа произвольной точности.

Примечания

  • Это конкурс популярности, будь креативным!
  • Скорость не нужна, но делает ее более интересной. Оптимизировать!
  • Я также заинтересован в том, чтобы увидеть самый короткий код. Вы получите +1 от меня!
  • Я запусту программу-победитель на суперкомпьютере, к которому у меня есть доступ!
  • Эта гипотеза считается верной, но это не значит, что мы не можем попробовать!
  • Питер Норвиг из Google тоже попытался решить эту проблему. Вы можете использовать его страницу в качестве руководства. У него есть небольшая программа на Python, которую вы можете использовать в качестве примера.
  • Какой-то другой парень (который также работает в Google) значительно улучшил подход Norvig, его страницу (с исходным кодом) можно найти здесь .
  • Мой вопрос SO, связанный с этим два года назад, также может быть полезным: найти все A ^ x в заданном диапазоне .

1
Суперкомпьютер? Теперь это круто. Есть ли шанс разделить деньги?
Aprıʇǝɥʇuʎs

@Synthetica Эта гипотеза уже была проверена с очень, очень, очень большими числами, так что это в основном для развлечения. Но, конечно, мы можем разделить деньги :)
Остин Хенли

2
«Это должно либо продолжаться вечно, либо разрешать ограниченную верхнюю границу (независимо от того, насколько она велика)». ... в отличие от каких альтернатив?
подземный

@undergroundmonorail Работает только для небольших номеров.
Остин Хенли

2
Малые числа являются конечной верхней границей.
подземный

Ответы:


4

Я пафосно ленивый (каламбур), но почему бы и нет ... кажется, выполняет правила.

Хаскелл, 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"

Это печатает 1 все комбинации, которые удовлетворяют свойству контрпримеров. Я использовал пакет control-monad -omega для диагонализации ℕ 6 ... можно было бы считать читерство библиотекой. Но, увидев, что кто-то позже опубликует ответ APL, где все это встроено в язык (или нет?), Я не слишком много об этом говорю ...

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


1 Так как он печатает кортежи в формате списка, то есть в одной строке, вам нужно отключить буферизацию вашего терминала, иначе вы не увидите, когда будет получен результат. В качестве альтернативы вы можете заменить printна, mapM_ printчтобы после каждого результата получать новую строку, очистка терминала с линейной буферизацией.

Чтобы протестировать программу, измените each[3..]на each[2..], тогда вы просто получите все не взаимно простые пифагорейские кортежи в результате.


2

C #, без петель

Хорошо, я просмотрел несколько этих ссылок, но, честно говоря, они были немного скучными. Я не заинтересован в том, чтобы оптимизировать его с помощью хеш-таблиц и еще много чего. Зачем мне это нужно? У тебя чертов суперкомпьютер!

Черт, я даже не хочу возиться с петлями! Это решение будет следовать правилу без циклов .

Обратите внимание, что код, который я собираюсь написать, не является хорошим кодом или кодом, который я написал бы в реальной жизни (на случай, если кто-нибудь из потенциальных работодателей прочитает это). Этот кодекс подчеркивает краткость и умение работать в повествовании, а также подчеркивает надлежащие условности, ритуалы, циклы и так далее.

Чтобы продемонстрировать, о чем я говорю, начнем с шокирующего класса с открытыми полями для хранения операндов уравнения:

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

Хорошо, мы начнем с того, что, вероятно, самая сложная задача. Нам нужно найти способ перестановки каждой комбинации этих операндов. Несомненно, есть способы сделать это более эффективно, чем проверка каждой перестановки, но я не могу быть обеспокоен, выясняя их. А зачем мне? У нас есть чертов суперкомпьютер!

Вот алгоритм, который я придумал. Это невероятно неэффективно и повторяет одни и те же операнды снова и снова, но кого это волнует? Суперкомпьютер!

  • Рассматривайте шесть операндов как число основания-2 и переставляйте каждую комбинацию.
  • Рассматривайте шесть операндов как число основания-3 и переставляйте каждую комбинацию.
  • Относитесь к шести операндам как к числу 4 и переставляйте каждую комбинацию.
  • (...)

Как сделать все это без петель? Легко! Просто реализовать IEnumerableи связанное IEnumeratorс откачкой перестановок. Позже мы будем использовать LINQ для запроса.

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

Теперь мы в деле! Все, что нам нужно сделать, это перечислить экземпляр BealOperandGeneratorи найти контрпример к гипотезе Била.

Наша следующая большая проблема заключается в том, что не существует встроенного способа поднять a BigIntegerдо степени a BigInteger. Есть BigInteger.Pow(BigInteger value, int exponent), и BigInteger.ModPow(BigInteger value, BigInteger exponent, BigInteger modulus), но нет способа поднять BigInteger, к власти другого BigInteger, по модулю бесконечности.

Какой блестящий гвоздь проблемы! Похоже, это было решено с помощью нашего IEnumerable/ IEnumeratorмолотка!

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;
    }
}

Теперь у нас есть метод расширения Pow, который можно вызывать для a BigIntegerи который принимает BigIntegerпоказатель степени без модуля.

Хорошо, давайте отступим. Как мы можем определить, является ли конкретный BealOperandsконтрпример гипотезы Била? Ну, две вещи должны быть правдой:

  • Операнды, включенные в эту формулу вверху страницы, должны образовывать истинное уравнение.
  • A, B и C НЕ должны иметь общий простой множитель (т.е. их GCD равен 1).

У нас есть то, что нам нужно, чтобы проверить первое условие. И оказывается, что второе условие гораздо проще проверить, чем кажется. BigIntegerпредоставляет прекрасный GreatestCommonDivisorметод, который позволяет нам удобно обходить весь кошмар, пытаясь реализовать это без циклов.

Итак, мы готовы написать метод, чтобы проверить, BealOperandsявляется ли контрпример. Вот оно...

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;
    }
}

И, наконец, мы можем объединить все это с помощью этого довольно изящного Mainметода:

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

2

Нет контрпримеров с C ^ Z <= 1.0E27.

По состоянию на февраль 2019 года я проверяю до C ^ Z <= 1.0E29 в предположении, что показатель степени «X» и / или «Y» должен быть> = 5.

Текущая версия этой программы («X» и / или «Y»> = 5) занимает меньше 1 секунды на AMD 2920X, чтобы найти все решения для C ^ Z <= 1.0E15. (Но все gcd (A, B, C)> = 2)

Подробности на http://www.durangobill.com/BealsConjecture.html

Я могу изменить текущий код (использует «C» и OpenMP) за эти пределы, но для его запуска потребуется более 128 ГБ ОЗУ. (Сотни процессоров также помогут. Тысячи процессоров будут еще лучше.) (Если у вас есть свободный доступ к чему-то подобному, пожалуйста, свяжитесь со мной.)

Мой адрес электронной почты находится на моей домашней странице http://www.durangobill.com


1
Если вы можете конкретизировать это с помощью некоторого кода, это может быть правильным ответом, в противном случае он, вероятно, лучше всего подходит в качестве комментария к вопросу. Однако в любом случае работа, которую вы проделали, впечатляет.
Οurous

Многие университеты имеют высокопроизводительные кластеры. Если вы обратились к одному из них, они могут предоставить вам доступ. Я видел слишком много кластеров, просто бездействующих!
Остин Хенли,

1

Второй вариант поисковой программы Била завершен. Результаты:

СZ<1026AИкс+ВYзнак равноСZ(Икс,Y)> =4

(Икс,Y)> =5СZ<1028AИкс+ВYзнак равноСZ(Икс,Y)> =5

Подробности на: http://www.durangobill.com/BealsConjecture.html

Следующие два вопроса: 1) Может ли суперкомпьютер расширить поиск? 2) Если бы суперкомпьютер мог расширить поиск, будет ли это практичным?

1) Чтобы расширить любой из вышеперечисленных поисков до 1.0E30, потребуется 300 ГБ ОЗУ на ядро, если ядра не могут совместно использовать 300 ГБ. Для каждого дополнительного дополнительного приращения экспоненциальной мощности, превышающей 1.0E30, объем требуемой оперативной памяти увеличивается как минимум в 2,2 раза.

2) Количество вычислительной мощности, необходимой для каждого последующего инкрементального увеличения показателя степени до 1,0E30 и более, умножает объединенное время ЦП примерно на 3,8. Поиск до 1.0E29 занял 2 недели с использованием 12 ядер. Время на суперкомпьютерах, как правило, не является «бесплатным», и вероятность того, что существуют какие-либо контрпримеры, очень мала.

В качестве руководства по эффективности кода на сайте durangobill.com/BealE29code.txt каждое из 12 ядер в среднем выполняло 220 миллионов итераций цикла в секунду для внутреннего цикла. (Среднее значение для двухнедельного прогона.) (Увеличение оперативной памяти сверх того, что было у меня, увеличило бы эту среднюю скорость почти в 2 раза.)

Я позволю Остину ответить 1) и 2), поскольку у него есть доступ к суперкомпьютеру, а у меня нет. (Если по какому-то удаленному случаю оба «1» и «2» являются «go», я могу предоставить код «C» с предупреждением о том, что я не знаком с многопоточными инструкциями для больших кластеров суперкомпьютеров.)


Можете ли вы использовать только один ответ на вопрос, а не распространять его на три? Вы знаете, что можете редактировать свои предыдущие ответы, верно?
Джо Кинг

Я ценю, что вы нашли контрпример, а затем не печатали его ... Кроме того, это не очень-то похоже на игру в гольф ...
Axman6

0

Пришлось поместить это в 2 комментария, чтобы заставить это соответствовать.

Основные массивы распределяются следующим образом:

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

(Вам понадобится 128 ГБ ОЗУ для этих массивов)

с:

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

«Base» на самом деле нужно 33 бита ( cbrt(1.0E29)) - дополнительный бит вставляется в «Power» (который требует только 7 бит).

Массивы работают аналогично хеш-таблице. Однако, поскольку они отсортированы по PRIME1 и используются только как справочные таблицы, вам не нужны связанные списки для доступа к ним. Таким образом, результатом является очень быстрый линейный поиск по времени, чтобы увидеть, является ли пробный A ^ X + B ^ Y = любым C ^ Z.

Таким образом, операторы в самом внутреннем цикле имеют только два цикла.

Операторы «Pragma» контролируют количество используемых процессорных ядер (в данном случае 12) - все могут получить доступ к единственной копии массивов.

Вот «основной» код (в «C») (Надеюсь, что комментарии соответствуют длине опубликованной строки. Если нет, скопируйте их и вставьте код в какой-то документ с более длинной длиной строки.)


В поле для комментариев я могу использовать только 600 символов, а для кода мне нужно 3000+. (Любые предложения?) (Я могу опубликовать код на своей веб-странице, если я не могу опубликовать его здесь.)
Билл Батлер

Я поместил здесь «основной» код «С». durangobill.com/BealE29code.txt Если ничего другого, то это пример того, «как это сделать» для многопоточной обработки в «C».
Билл Батлер

1
Добро пожаловать на сайт. Хотя поля для комментариев ограничены 600 символами, ваш ответ - нет. Вы должны быть в состоянии вписать свой код в свой ответ легко. Если вы не пытаетесь обрезать комментарии. Также я переформатировал ваш ответ, чтобы использовать блоки кода. Это можно сделать с 4 пробелами, как я сделал. Когда вы перемещаете свой код к своему ответу, вы должны поместить его в блок кода, иначе он будет полностью нечитаемым.
Пост Рок Гарф Хантер
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.