/// <summary> /// (有限)位相空間かどうか。集合族が開集合族の定義を満たすかどうか。 /// /// </summary> /// <param name="subsets">集合族</param> /// <param name="universe">全体集合・台集合</param> /// <returns>(有限)位相空間</returns> public static bool isTopological <TEnum>(this FamilyOfSubsets <TEnum> subsets, FiniteSet <TEnum> universe) where TEnum : Enum { //集合がなければ偽 if (subsets == null || subsets.Count == 0) { return(false); } //空集合がなければ偽 else if (!subsets.isContainsEmpty()) { return(false); } //台集合がなければ偽 else if (!subsets.Contains(universe)) { return(false); } //和集合について閉じてなければ偽 else if (!subsets.isSumComplete()) { return(false); } //交叉について閉じてなければ偽 else if (!subsets.isProductComplete()) { return(false); } //条件を満たしているので真 return(true); }
/// <summary> /// 部分集合族の包含関係 ⊆ から 自己関係 R を生成するメソッド /// </summary> /// <typeparam name="TEnum"></typeparam> /// <param name="subsets">部分集合族</param> /// <param name="universe">全体集合</param> /// <returns></returns> public static EndoRelation <FiniteSet <TEnum> > CreateSubsetRelation <TEnum>(this FamilyOfSubsets <TEnum> subsets, FiniteSet <TEnum> universe) where TEnum : Enum { if (!subsets.isUniverseOK(universe)) { throw new ArgumentException("全体集合が、部分集合族の要素である、集合の要素を網羅していません"); } var retRel = new EndoRelation <FiniteSet <TEnum> >(); //自己関係の全体集合は冪集合(もとの台集合の部分集合族なので) retRel.SetUniverse(universe.PowerSet()); //要素となる集合を格納 foreach (FiniteSet <TEnum> subsetX in subsets) { foreach (FiniteSet <TEnum> subsetY in subsets) { //X⊆Y ⇔ X R Y という定義で自己関係Rを定義 if (subsetX.IsSubsetOf(subsetY)) { retRel.Add((subsetX, subsetY)); } } } return(retRel); }
/// <summary> /// 台集合からなあらゆる開集合系を網羅したリストを生成するメソッド。の改良版。 /// https://twitter.com/noshi91/status/1342137767615066113?s=20 /// というアドバイスをもらったのでそれを転写。 /// ビット演算を用いてなんとかしたが、それでもやはり実行がとてつもなく重く、時間もかかる。 /// そのため、このメソッドで生成したリストを別途jsonやxmlに保存したほうがよい。 /// </summary> /// <typeparam name="TEnum"></typeparam> /// <param name="originalSet">元の集合(台集合)</param> /// <returns>開集合系リスト</returns> public static SortedSet <FamilyOfSubsets <TEnum> > OpenSetsListVer2 <TEnum>(this FiniteSet <TEnum> originalSet) where TEnum : Enum { //Ver1では openSetsを作る→openSetsが開集合系の可能性を満たすかどうか判定していたが… //まず冪集合をつくる すでに重いと思う FamilyOfSubsets <TEnum> PowerSet = originalSet.PowerSet(); //返すリスト var retList = new SortedSet <FamilyOfSubsets <TEnum> >(); BigInteger ans = 0; void dfs(BigInteger s, int i) { if (i == 32) { string printFamilySets = ""; for (int t = 0; t != 32; ++t) { if (((s >> t) & 1) == 0) { continue; } printFamilySets += "{"; for (int k = 0; k != 5; ++k) { if (((t >> k) & 1) == 1) { printFamilySets += ","; } } printFamilySets += "},"; } Console.WriteLine(printFamilySets); ans += 1; return; } dfs(s, i + 1); for (int t = 0; t != i; ++t) { if (((s >> t) & 1) == 1 && ((s >> (t & i)) & 1) == 0) { return; } } dfs(s | (1 << i), i + 1); }; dfs(0, 0); Console.WriteLine(retList.Count + "個"); return(retList); }
/// <summary> /// 集合族に空集合があるかどうかを判定(集合族自体が空なら偽) /// </summary> /// <param name="subsets">集合族</param> /// <returns>空集合があるかどうか</returns> public static bool isContainsEmpty <TEnum>(this FamilyOfSubsets <TEnum> subsets) where TEnum : Enum { //集合がなければ偽 if (subsets == null || subsets.Count == 0) { return(false); } return(subsets.Contains(new FiniteSet <TEnum>())); }
/// <summary> /// 与えた集合が、集合族の全体集合の必要条件を満たしているかどうか /// ∀subset∈Subsets ∀element∈subset (element ∈ universe) /// /// </summary> /// <param name="subsets">集合族</param> /// <param name="universe">全体集合かどうか判定する集合</param> /// <returns>与えた集合は全体集合の必要条件を満たす</returns> public static bool isUniverseOK <TEnum>(this FamilyOfSubsets <TEnum> subsets, FiniteSet <TEnum> universe) where TEnum : Enum { foreach (FiniteSet <TEnum> subset in subsets) { foreach (TEnum element in subset) { if (!universe.Contains(element)) { return(false); } } } return(true); }
/// <summary> /// ∩-完備,σ乗法性があるかどうか(共通部分∩について閉じているかどうか) /// </summary> /// <param name="subsets">集合族</param> /// <returns>∩-完備</returns> public static bool isProductComplete <TEnum>(this FamilyOfSubsets <TEnum> subsets) where TEnum : Enum { foreach (FiniteSet <TEnum> subset1 in subsets) { foreach (FiniteSet <TEnum> subset2 in subsets) { FiniteSet <TEnum> andSet = subset1.And(subset2); if (!subsets.Contains(andSet)) { return(false); } } } return(true); }
/// <summary> /// 部分集合族の総乗を取る /// </summary> /// <param name="subsets">部分集合族</param> /// <returns>総乗</returns> public static FiniteSet <TEnum> ProductOfSeq <TEnum>(this FamilyOfSubsets <TEnum> subsets) where TEnum : Enum { //集合がなければ空集合を返す if (subsets == null || subsets.Count == 0) { return(new FiniteSet <TEnum>()); } //まず最大値を設置 var retSet = subsets.Max; foreach (FiniteSet <TEnum> subset in subsets) { retSet = retSet.And(subset); } return(retSet); }
/// <summary> /// 離散位相かどうか。 /// </summary> /// <param name="subsets">集合族</param> /// <param name="universe">全体集合・台集合</param> /// <returns>離散位相である</returns> public static bool isDiscrete <TEnum>(this FamilyOfSubsets <TEnum> subsets, FiniteSet <TEnum> universe) where TEnum : Enum { //まず位相空間でなければ偽 if (!subsets.isTopological(universe)) { return(false); } //濃度が2^universe.Countでなければ偽 else if (subsets.Count != ((BigInteger)1 << universe.Count)) { return(false); } //条件を満たしているので真 return(true); }
/// <summary> /// △-完備かどうか(対称差△について閉じているかどうか) /// </summary> /// <param name="subsets">集合族</param> /// <returns>△-完備</returns> public static bool isSymDiffComplete <TEnum>(this FamilyOfSubsets <TEnum> subsets) where TEnum : Enum { foreach (FiniteSet <TEnum> subset1 in subsets) { foreach (FiniteSet <TEnum> subset2 in subsets) { FiniteSet <TEnum> xorSet = subset1.Xor(subset2); if (!subsets.Contains(xorSet)) { return(false); } } } return(true); }
/// <summary> /// 部分集合族の総和を取る /// </summary> /// <param name="subsets">部分集合族</param> /// <returns>総和</returns> public static FiniteSet <TEnum> SumOfSeq <TEnum>(this FamilyOfSubsets <TEnum> subsets) where TEnum : Enum { //集合がなければ空集合を返す if (subsets == null || subsets.Count == 0) { return(new FiniteSet <TEnum>()); } //まず空集合を設置 var retSet = new FiniteSet <TEnum>(); foreach (FiniteSet <TEnum> subset in subsets) { retSet = retSet.Or(subset); } return(retSet); }
/// <summary> /// 補-完備かどうか(補集合cについて閉じているかどうか) /// </summary> /// <param name="subsets">集合族</param> /// <param name="universe">全体集合</param> /// <returns>補-完備</returns> public static bool isComplementComplete <TEnum>(this FamilyOfSubsets <TEnum> subsets, FiniteSet <TEnum> universe) where TEnum : Enum { if (!subsets.isUniverseOK(universe)) { throw new ArgumentException("全体集合が、部分集合族の要素である、集合の要素を網羅していません"); } foreach (FiniteSet <TEnum> subset in subsets) { FiniteSet <TEnum> diffSet = universe.Diff(subset); if (!subsets.Contains(diffSet)) { return(false); } } return(true); }
/// <summary> /// \-完備かどうか(差集合\について閉じているかどうか) /// </summary> /// <param name="subsets">集合族</param> /// <returns>\-完備</returns> public static bool isDiffComplete <TEnum>(this FamilyOfSubsets <TEnum> subsets) where TEnum : Enum { foreach (FiniteSet <TEnum> subset1 in subsets) { foreach (FiniteSet <TEnum> subset2 in subsets) { FiniteSet <TEnum> diffSet = subset1.Diff(subset2); IEqualityComparer <FiniteSet <TEnum> > comparer = new FiniteSetComparer <TEnum>(); if (!subsets.Contains(diffSet, comparer)) { return(false); } } } return(true); }
public int CompareTo([AllowNull] FamilyOfSubsets <TEnum> other) { //値参照して同じなら0 if (this.SequenceEqual(other)) { return(0); } //要素数で比較 if (this.Count > other.Count) { return(1); } else if (this.Count < other.Count) { return(-1); } //要素数が同じ場合、若いFiniteSet<TEnum>を持っているほうが先に表示 foreach (var set1 in this) { foreach (var set2 in other) { //同じ要素を比較した場合、次のset1を比較 if (set1.SequenceEqual(set2) || set1.CompareTo(set2) == 0) { break; } else if (set1.CompareTo(set2) == 1) { return(1); } else if (set1.CompareTo(set2) == -1) { return(-1); } } } //ここまで来ると同じの可能性があるが、そもそも同じであることは冒頭で比較したのでここまでくるとおかしい throw new NotImplementedException(); }
/// <summary> /// 与えた有限集合の密着位相となる部分集合族を返す /// </summary> /// <param name="originalSet">元の集合(台集合)</param> /// <returns>密着位相となる部分集合族 {originalSet,Empty}</returns> public static FamilyOfSubsets <TEnum> IndiscreteFamily <TEnum>(this FiniteSet <TEnum> originalSet) where TEnum : Enum { //空集合なら空集合の集合だけ返す つまり{{}} if (originalSet == null || originalSet.Count == 0) { return(new FamilyOfSubsets <TEnum>() { new FiniteSet <TEnum>() }); } var retFamily = new FamilyOfSubsets <TEnum>(); retFamily.Add(originalSet); retFamily.Add(new FiniteSet <TEnum>()); return(retFamily); }
/// <summary> /// 集合の濃度を返す /// </summary> /// <typeparam name="TEnum"></typeparam> /// <param name="set">集合</param> /// <returns>濃度</returns> public static int Cardinality <TEnum>(this FamilyOfSubsets <TEnum> subsets) where TEnum : Enum { return(subsets.Count); }
/// <summary> /// 台集合からなあらゆる開集合系を網羅したリストを生成するメソッド。 /// 2^(2^n - 2)という計算をしているため実行がとてつもなく重く、時間もかかる。 /// そのため、このメソッドで生成したリストを別途jsonやxmlに保存したほうがよい。 /// </summary> /// <typeparam name="TEnum"></typeparam> /// <param name="originalSet">元の集合(台集合)</param> /// <returns>開集合系リスト</returns> public static SortedSet <FamilyOfSubsets <TEnum> > OpenSetsList <TEnum>(this FiniteSet <TEnum> originalSet) where TEnum : Enum { //まず冪集合をつくる すでに重いと思う FamilyOfSubsets <TEnum> PowerSet = originalSet.PowerSet(); //返すリスト var retList = new SortedSet <FamilyOfSubsets <TEnum> >(); //まず密着位相をつくる //var family = originalSet.IndiscreteFamily(); //クソでかくなるのでビット演算を使わざるを得なかった BigInteger indiscreteIndex = 4; //扱ってる対象が密着空間かどうか bool isDiscrete = false; // 1 << n は 2^n (2のn乗) for (BigInteger index = 0; index < ((BigInteger)1 << (1 << originalSet.Count) - 2); index++) { //離散空間の次の位相空間のナンバーを記録する //この位相空間は密着位相である if (isDiscrete) { indiscreteIndex = index; isDiscrete = false; } //開集合系を初期化 var openSets = new FamilyOfSubsets <TEnum>(); //空集合を入れる。これは必ず入れる openSets.Add(new FiniteSet <TEnum>()); //台集合を入れる。これも必ず入れる openSets.Add(originalSet); //要素の有無を判定し、追加。 for (int j = 0; j < (1 << originalSet.Count); j++) { if ((index & ((BigInteger)1 << j - 1)) != 0) { //ElementAtがクソ重いのでどうにかすべき openSets.Add(PowerSet.ElementAt(j)); } } //位相空間かどうか判定を行う。位相空間でなければ何もしない if (openSets.isTopological(originalSet)) { //開集合系の条件を満たす retList.Add(openSets); bool Dis = openSets.isDiscrete(originalSet); System.IO.StreamWriter sw = new System.IO.StreamWriter( "test.txt", // 出力先ファイル名 true, // 追加書き込み Encoding.UTF8); //Console.SetOut(sw); // 出力先(Outプロパティ)を設定 Console.WriteLine(index.ToString("x4") + ":" + index.ToString() + ":" + retList.Count + ":" + Dis + ":" + openSets.ToString()); //離散空間の場合、しばらくの間は位相空間となる数字が出てこないので、 //bit31の値を倍にする //if (Dis && bit31 >= 4) //{ // isDiscrete = true; // bit31 = indiscreteIndex * 2 - 1; //} sw.Dispose(); // ファイルを閉じてオブジェクトを破棄 } openSets = null; } Console.WriteLine(retList.Count + "個"); return(retList); }