让Beal拿走$ 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的Peter Norvig也尝试过此问题。您可以使用他的页面作为指导。他有一个简短的Python程序,您可以作为示例。
  • 其他人(也恰好在Google工作)已经大大改进了Norvig的方法,可以在此处找到其页面(带有源代码)。
  • 我两年前与此相关的SO问题也可能会有所帮助:在给定范围内所有A ^ x

1
超级计算机?现在很酷。有机会分拆现金吗?
ɐɔıʇǝɥʇuʎs

@Synthetica这个猜想已经通过非常非常大的数字进行了测试,因此这主要是为了好玩。但是我们当然可以分摊现金:)
奥斯汀·亨利

2
“它应该永远持续下去,或者允许一个有限的上限(无论大小)。” ...而不是其他选择?
地下

@undergroundmonorail仅适用于少量数字。
奥斯汀·亨利

2
小数字是有限的上限。
地下

Answers:


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个满足counterexample属性的所有组合。我使用了control-monad-omega软件包为diagonalisingℕ 6 ...可能被认为是库作弊。但是看到有人以后会在APL答案中发布所有这些内容已内置在语言中的信息(不是吗?),我对此不做过多介绍...

当然,该程序太慢了(天真的用尽,并且链表作为数据结构),以至于无法真正产生反例,但是Haskell本身实际上可以实现不错的性能。


1因为它以列表格式(即一行)打印元组,所以您需要关闭终端的缓冲,否则将看不到结果何时出现。或者,您也可以替换printmapM_ 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() { }
}

现在我们开始营业!我们所需要做的就是枚举BealOperandGeneratorBeal猜想的一个实例并找到一个反例。

我们的下一个大问题是,似乎没有一种将a提升为a BigInteger的幂的内置方法BigInteger。有BigInteger.Pow(BigInteger value, int exponent)BigInteger.ModPow(BigInteger value, BigInteger exponent, BigInteger modulus),但没有方法将a提升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,可以在上调用它BigInteger,并采用BigInteger指数且没有模数。

好,让我们退后一步。我们怎么知道一个特定的BealOperands某件事是否是Beal猜想的反例?好吧,有两件事必须是正确的:

  • 将操作数插入页面顶部的该公式时,必须形成一个真方程。
  • A,B和C不得具有共同的质因数(即,它们的GCD为1)。

我们已经具备了检查第一个条件所需的条件。事实证明,第二种情况比听起来容易得多。BigInteger提供一个可爱的GreatestCommonDivisor方法,它使我们可以方便地回避试图实现无循环的整个噩梦。

因此,我们准备编写一种方法来检查a 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年2月起,我将根据“ X”和/或“ Y”指数必须大于等于5的假设签出C ^ Z <= 1.0E29。

该程序的当前版本(“ X”和/或“ Y”> = 5)在AMD 2920X上花费不到1秒的时间才能找到C ^ Z <= 1.0E15的所有解决方案。(但是所有的gcd(A,B,C)> = 2)

有关详细信息,请访问http://www.durangobill.com/BealsConjecture.html

我可以修改当前代码(使用“ C”和OpenMP)以超出这些限制,但是要运行它需要128GB以上的RAM。(数百个CPU也会有所帮助。成千上万个CPU甚至会更好。)(如果您可以免费使用这样的东西,请与我联系。)

我的电子邮件地址在我的主页上,网址http://www.durangobill.com


1
如果您可以用一些代码充实一下,这可能是一个有效的答案,否则可能最适合作为对该问题的注释。但是,无论哪种方式,您所做的工作都令人印象深刻。
20:54

许多大学都有高性能的集群。如果您与他人联系,他们也许可以授予您访问权限。我看到太多的集群只是空转!
奥斯汀·亨利

1

Beal搜索程序的第二个版本已完成。结果是:

1)没有反例Cž<1026。所有通用解决方案的完整列表一种X+ÿ=Cž 至少有一个指数 Xÿ> =4可以在以下位置看到:http : //www.durangobill.com/BealXgt3e27.txt

2)如果您假设至少有指数 Xÿ 一定是 > =5,没有反例 Cž<1028。所有通用解决方案的完整列表一种X+ÿ=Cž 至少有一个指数 Xÿ> =5且C ^ Z <1.0E29可以在以下网址查看:http ://www.durangobill.com/BealXgt4e29.txt

有关详细信息,请访问:http : //www.durangobill.com/BealsConjecture.html

接下来的两个问题是:1)超级计算机可以扩展搜索范围吗?2)如果超级计算机可以扩展搜索范围,是否可行?

1)要将以上任一搜索扩展到1.0E30,除非内核可以共享300GB,否则每个内核将需要300GB RAM。对于超过1.0E30的指数幂,每增加一次增量,所需的RAM量将增加至少2.2倍。

2)指数进一步增加到1.0E30或超过1.0E30,所需的处理能力将使总CPU时间乘以约3.8。使用12个核心,搜索到1.0E29花费了2周的时间。超级计算机时间通常不是“空闲”的,几乎没有任何反例的前景。

作为durangobill.com/BealE29code.txt上代码效率的指南,12个内核中的每个内核平均每秒对内部循环进行2.2亿次循环迭代。(平均是2周的运行时间。)(RAM内存的增加超过我的能力,则平均速度将提高2倍。)

我将让奥斯汀回答1)和2),因为他可以使用超级计算机,但我没有。(如果偶然)1)和2)都是“执行”,则可以向“ 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);

(这些阵列需要128GB的RAM)

与:

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

“基本”实际上需要33位(cbrt(1.0E29))-多余的位填充在“电源”中(仅需要7位)。

数组的操作类似于哈希表。但是,由于它们是按PRIME1排序的,并且仅用作查找表,因此不需要链接列表即可访问它们。因此,结果是非常快速的线性时间查找,以查看试验A ^ X + B ^ Y =任何C ^ Z。

因此,最内部循环中的语句仅深两个循环。

“ Pragma”语句控制所使用的多处理核心的数量(在本例中为12)-全部都可以访问阵列的单个副本。

这是“主”代码(在“ C”中)(希望注释适合所发布的行长。如果不行,请将其复制出来,然后将代码粘贴到行长更长的某些文档中。)


注释框只允许我使用600个字符,而我需要3,000+个代码。(有什么建议吗?)(如果无法在此处发布代码,则可以在网页上发布代码。)
Bill Butler

我将“主要”“ C”代码放在这里。durangobill.com/BealE29code.txt 如果没有别的,它就是“ C”中多线程处理的“如何做”的例子。
比尔·巴特勒

1
欢迎来到该网站。虽然注释框限制为600个字符,但您的答案不是。您应该能够轻松地将代码适合您的答案。如果您不尝试修剪掉注释。我也重新格式化了您使用代码块的答案。可以像我一样用4个空格完成这些操作。将代码移至答案时,应将其放在代码块中,否则将完全无法读取。
发布Rock Garf Hunter,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.