Ejemplo n.º 1
0
        /// <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>
        /// 台集合からなあらゆる開集合系を網羅したリストを生成するメソッド。
        /// 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);
        }