我正在为离散数学设计一个类库,我想不出实现infinite set的方法。
到目前为止我所拥有的是:我有一个抽象基类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's methods的方法,其中最有问题的是枚举方法和IsSubsetOf方法。
答案 0 :(得分:6)
无法完全实现ISet<T>
无数无限集。
这是一个证据(由Bertrand Russell提供):
假设您已经创建了一个类MySet<T>
,它可以表示无数的无限集。现在让我们考虑一些MySet<object>
个对象。
我们标记了一个特定的MySet<object>
,称之为instance
,“异常”如果:
instance.Contains(instance)
返回true。
同样,如果符合以下条件,我们会将instance
标记为“ normal ”:
instance.Contains(instance)
返回false。
请注意,这种区别是针对所有instance
明确定义的。
现在考虑一个名为MySet<MySet<object>>
的{{1}}实例。
我们将paradox
定义为paradox
,其中包含MySet<MySet<object>>
的所有普通实例。
MySet<object>
应该返回什么?
如果它返回paradox.Contains(paradox)
,则true
异常,并且在自行调用时应该返回paradox
。
如果它返回false
,那么false
正常,并且在自己调用时应该返回paradox
。
无法实施true
来解决此悖论,因此无法为所有可能的不可数集合全面实施Contains
。
现在,如果您将ISet<T>
的基数限制为等于或小于连续体(| R |)的基数,那么您将能够绕过这个悖论。
即使这样,你也无法实现MySet<T>
或类似的方法,因为这样做会等同于解决暂停问题。 (请记住,所有Contains
程序的集合的基数等于| Z |&lt; | R |。)
修改强>
为了更加彻底,这里是对我的断言的解释,“这样做将等同于解决停止问题。”
考虑由所有C#程序(作为字符串)组成的C#
,它在有限的时间内停止(假设它们为任何输入停止,确切地说)。称之为MySet<string>
。该集合是*递归可枚举的“,这意味着你可以在其上实现paradox2
(不容易,但它是可能的。)这也意味着它被很好地定义。但是,这个集合不是”可判定的“,因为它补语不是递归可枚举的。
按如下方式定义C#程序:
GetEnumerator
编译上述程序,并将其作为输入传递给自己。会发生什么?
如果您的using ... //Everything;
public static class Decider {
private MySet<string> _haltingSet = CreateHaltingSet();
static void Main(string [] args) {
Console.WriteLine(_haltingSet.Contains(args[0]));
}
}
方法已正确实施,那么您已解决了暂停问题。但是,我们知道这是不可能的,因此我们只能得出结论,即使对于可数无限的集合,也无法正确实现Contains
,。
您可以限制Contains
班级适用于所有decidable sets.但是,您仍然会遇到各种问题从不停止有限的时间。
作为一个例子,让我们假装我们有一个名为MySet<T>
的任意精度实数类型,让我们让Real
成为nonHalting
的一个实例,其中包含所有非平凡的零。 Riemann Zeta函数(这是一个可判定的集合)。如果你能够在MySet<Real>
上正确实现IsProperSubsetOf
以在有限的时间内返回,当通过所有复数的集合与实部1/2(也是可判定集)时,那么你将获胜一个Millennium Prize.
答案 1 :(得分:2)
你将不得不概括Set的意思。
如果您将拥有无限集,则无法对其进行有意义的枚举,因此您不会使用枚举操作来定义集合运算。
如果您根据Set<f>
方法定义bool IsMember(f obj)
,则可以将其用于无限集。
您可以将两个集合的并集或交集定义为两个集合的逻辑和/或IsMember方法。
答案 2 :(得分:2)
代表无数无限集
让我们在实践中如何完成这一陈述。例如,当询问天气时,集合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种,你可以在无限范围内专门定义它们的相互作用,然后使用更简单的有限实现比较。
答案 3 :(得分:0)
你究竟打算用它做什么。 你无法枚举它。
我认为我将其视为普遍集的后代。
我想我会从另一端开始
定义一个通用集,其中Ismember始终为true 然后是IsMember为真的后代,如果它是自然数的表示 {1,2,3,4}是N的进一步限制
无论如何想到
答案 4 :(得分:0)
这可能有很多限制,就像符号表达式处理一样。
这是一个小例子:
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;
}
}
}