问题 如何实现无限集类?


我正在为离散数学设计一个类库,我想不出一种实现方法的方法 无限集

到目前为止我所拥有的是:我有一个抽象基类Set,它实现了接口ISet。对于有限集,我派生了一个有限集类,它实现了每个集合方法。我可以这样使用它:

FiniteSet<int> set1 = new FiniteSet<int>(1, 2, 3);
FiniteSet<int> set2 = new FiniteSet<int>(3, 4, 5);
Console.WriteLine(set1); //{1, 2, 3}
Console.WriteLine(set2); //{3, 4, 5}

set1.UnionWith(set2);
Console.WriteLine(set1); //{1, 2, 3, 4, 5}

现在我想代表一个无限集。我有从set,InfiniteSet派生另一个抽象类的想法,然后使用该库的开发人员必须从InfiniteSet派生来实现他们自己的类。我会提供常用的套装,比如N,Z,Q和R.

但我不知道我如何实现像Subset和GetEnumerator这样的方法 - 我甚至开始认为这是不可能的。如何以实际方式枚举无限集,以便可以将其与另一个无限集相交/联合?如何在代码中检查N是R的子集?至于基数问题..嗯,这可能是一个单独的问题。

所有这些使我得出结论,我实现无限集的想法可能是错误的方法。我非常感谢你的意见:)。

编辑:为了清楚起见,我也想代表无数的无限集。

Edit2:我认为重要的是要记住最终目标是实现ISet,这意味着任何解决方案都必须提供(应该)实现所有方法的方法。 ISet的方法,最有问题的是枚举方法和IsSubsetOf方法。


3955
2017-07-25 22:33


起源

创建无限集很容易 yield return  msdn.microsoft.com/en-us/library/9k7k7cf0.aspx - asawyer
@asawyer我真的没有看到这与这里的任何问题有什么关系,除了实现枚举 - 这实际上仍然存在实现它的问题。 - Daniel
创建一个 可数 无限集很容易 yield return。 - Michael Graczyk
@Daniel迈克尔说的话。对不起,如果我误解了这个问题。 - asawyer
根据定义,您无法枚举不可数集。如果你愿意放弃枚举,那么实现集合应该是微不足道的(只需要一个检查成员资格的谓词。交叉点和两个谓词,以及它们的联合或它们)。 - Michael Graczyk


答案:


无法完全实施 ISet<T> 无数无限集。

这是一个证明(由Bertrand Russell提供):

假设您已经创建了一个类 MySet<T> 这可以代表一个无数无限的集合。现在让我们考虑一些 MySet<object> 对象。

我们标注一个特定的 MySet<object>, 叫它 instance,“不正常“如果:

instance.Contains(instance) 返回true。

同样,我们会标记 instance 作为“正常“如果:

instance.Contains(instance) 返回false。

请注意,这种区别是为所有人明确定义的 instance

现在考虑一个实例 MySet<MySet<object>> 叫 paradox

我们定义 paradox 作为 MySet<MySet<object>> 其中包含所有可能的 正常 的实例 MySet<object>

什么应该 paradox.Contains(paradox) 返回?

如果它返回 true, 然后 paradox 是 不正常 应该已经回来了 false 当被召唤时。

如果它返回 false 然后 paradox 是 正常,应该已经返回了 true 当被召唤时。

没有办法实施 Contains 解决这个矛盾,所以没有办法完全实现 ISet<T> 对于所有可能的无数集。


现在,如果你限制了基数 MySet<T> 等于或小于连续体(| R |)的基数,那么你就能解决这个矛盾。

即使这样,你也无法实现 Contains 或类似的方法,因为这样做相当于解决停止问题。 (记住所有的一套 C#程序的基数等于| Z | <| R |。)

编辑

为了更加彻底,这里是对我的断言的解释,“这样做将等同于解决停止问题。”

考虑一下 MySet<string> 它包含所有C#程序(作为字符串),它们在有限的时间内停止(假设它们停止输入任何输入,确切地说)。叫它 paradox2。该集合是*递归可枚举的“,这意味着您可以实现 GetEnumerator 在它上面(不容易,但有可能)。这也意味着它定义明确。但是,这个集合不是“可判定的”,因为它的补码不是递归可枚举的。

定义C#程序如下:

using ... //Everything;

public static class Decider {

    private MySet<string> _haltingSet = CreateHaltingSet();

    static void Main(string [] args) {
        Console.WriteLine(_haltingSet.Contains(args[0]));
    }
}

编译上面的程序,并将其作为输入传递给自己。怎么了?

如果你的 Contains 方法正确实施,然后你已经解决了暂停问题。但是,我们知道这是不可能的,因此我们只能得出结论认为无法正确实施 Contains即使是可数无限的集合。

你可以限制你的 MySet<T> 为所有人工作的课程 可判定的集合。  但是,您仍然会遇到函数的各种问题 决不 在有限的时间内停止。

举个例子,让我们假装我们有一个叫做的任意精度实数类型 Real,让我们来吧 nonHalting 是一个实例 MySet<Real> 其中包括Riemann Zeta函数的所有非平凡零点(这是一个可判定的集合)。如果你能正确实施 IsProperSubsetOf 上 nonHalting 当通过所有复数的集合与实部1/2(也是一个可判定的集合)时,在有限的时间内返回,那么你将赢得一个 千禧奖。


6
2017-07-25 23:16



“现在,如果你将MySet <T>的基数限制为等于或小于连续体(| R |)的基数,那么你将能够解决这个矛盾。”我愿意这样做(我必须这样做,不要我:P?)。但IsSubsetOf如何等同于解决停止问题? - Daniel
我会试着弄清楚一个例子。 - Michael Graczyk
得到它,添加为编辑。 - Michael Graczyk
很好的答案 - 谢谢。 - Daniel


你将不得不概括Set的意思。

如果您将拥有无限集,则无法对其进行有意义的枚举,因此您不会使用枚举操作来定义集合运算。

如果你定义一个 Set<f> 就...而言 bool IsMember(f obj) 方法,它可以用于无限集。

您可以将两个集合的并集或交集定义为两个集合的逻辑和/或IsMember方法。


2
2017-07-25 22:43



我不确定我理解 - 考虑到R的IsMember和N的IsMember,你怎么能确定N是R的一个子集..你怎么能与它们相交,或者将它们联合起来? - Daniel
取决于是否输入R.如果R是自然数,那么N union R是N,N和R是R. - Tony Hopkinson
@TonyHopkinson我在谈论你如何在代码中做到这一点:P ..我知道如何在纸上做到这一点。而且,R不仅包含自然数 - 它具有无数更多的非自然数。 - Daniel
@Daniel - 交叉和联合很容易:(一个联合B).IsMember(f)=(A.IsMember(f)|| B.IsMember(f)); (交叉点B).IsMember(f)=(A.IsMember(f)&& B.IsMember(f))。对于无限集,测试A是B的子集并不容易(事实上,在最常见的情况下,如另一个答案所示)是不可能的;你必须象征性地表示IsMember谓词并证明A的谓词意味着B. - antlersoft
@Daniel。我也是如此,这就像数学一样必须是符号和规则。没有人证明N是R的子集,通过枚举N的每个记忆并看看它是否是R的成员,他们...... - Tony Hopkinson


代表无数的无限集

让我们在实践中如何完成这一陈述。例如,当询问天气时,集合A是集合Z(正整数)的子集,主题不是Z.Z中的每个数字都不被分析。分析的是有问题的集合A.因为无法将Ak(一个子k,其中k是1和| A |之间的数字)与Z(无限)的每个值进行比较,所以A的每个值都必须是与构成Z的属性相比较。如果A中的每个值都满足Z的属性,则A是Z的子集。

你怎么能在代码R union N中表示

与上述过程相同。 R的属性是“任何实数” - 在代码中,这可能是“任何不会抛出异常的双重”(显然 Math.Pow(-1,.5) 会产生问题,因此不会出现在R中。 N的属性是“任何整数” - 在代码中,这可以是Math.Floor!= Math.Ceiling的任何数字。这两者的结合是它们的属性的结合。任何符合R或N属性的数字 - 在代码中,这将是任何不会抛出异常的数字 要么 哪个Math.Floor!= Math.Ceiling。

概要

要表示不可数的无限集,请使用它们的属性而不是它们的值。


编辑

N⊆R?

让我们回到属性的想法,因为这是我追求的主题。 N是R的子集吗?要使N成为R的子集,则N的属性必须满足 所有 R的属性。属性列表需要准确。为了表示无穷大的数值,我建议使用一个包含可空int数和普通int符号的类。

public class Infinite
{
 public int? Number { get; set; }
 public int Sign { get; set; }
}

沿着这些方向的东西。 Number.Value == null意味着无限。符号可用于显示负(-1),+ - (0)或正(1)。

回到R情境的N子集。除了前面列出的属性之外,N还将Infinite.Number == null和Infinite.Sign == 0作为其属性的边界。就像R.所以,N能够满足边界属性。接下来将是上面定义的属性。我实际上被困在这里。我不确定如何在代码中证明.Floor == .Ceiling的每个数字都不会导致异常。但是,由于这些类型的超集(Rational,Irrational,Integer,Real,Complex,Imaginary,Transcendental,Algebraic,Natural)中只有9种,您可以在无限范围内专门定义它们的交互,然后使用更简单的有限实现比较。


2
2017-07-25 23:19



这解决了工会化问题,在我看来这是最微不足道的问题,但仍然不是N是R的一个子集?问题,或枚举问题。我很欣赏(写得很好)的答案:)。 - Daniel


你究竟打算用它做什么 你无法枚举它。

我认为我将它当作普遍集的后代。

我想我会从另一端开始

定义一个通用集,其中Ismember始终为true 然后是IsMember为真的后代,如果它是自然数的表示 {1,2,3,4}是N的进一步限制

无论如何一个想法


0
2017-07-25 23:00





这可能有很多限制,就像符号表达式处理一样。

这是一个小例子:

class IntSet
{
    int m_first;
    int m_delta;

    public IntSet(int first, int delta)
    {
        m_first = first;
        m_delta = delta;
    }

    public override string ToString()
    {
        StringBuilder sb = new StringBuilder();

        sb.Append('[');
        sb.Append(m_first);
        sb.Append(',');
        sb.Append(m_first + m_delta);
        sb.Append(',');
        sb.Append("...");
        sb.Append(']');

        return sb.ToString();
    }

    public IEnumerable<int> GetNumbers()
    {
        yield return m_first;

        int next = m_first;

        while (true)
        {
            next += m_delta;

            yield return next;
        }
    }
}

0
2017-07-26 00:36