private void __SetGLinkLstSet(UGLink_unit LKx, int SW, int rc, int no1, int no2)             // in-cell link
        {
            UGLink_pair LK1 = new UGLink_pair(LKx, SW, rc, no2);

            if (GLK_connection[rc, no1] == null)
            {
                GLK_connection[rc, no1] = new List <UGLink_pair>();
            }
            GLK_connection[rc, no1].Add(LK1);
            UGLink_pair LK2 = new UGLink_pair(LKx, SW, rc, no1);

            if (GLK_connection[rc, no2] == null)
            {
                GLK_connection[rc, no2] = new List <UGLink_pair>();
            }
            GLK_connection[rc, no2].Add(LK2);
        }
        private void __SetGLinkLstSet(UGLink_unit LKx, int SW, int tfx, int no, UCell UC1, UCell UC2)       // cell-cell link
        {
            int rc1 = UC1.rc, rc2 = UC2.rc;

            UGLink_pair LK1 = new UGLink_pair(LKx, SW, rc2, no);

            if (GLK_connection[rc1, no] == null)
            {
                GLK_connection[rc1, no] = new List <UGLink_pair>();
            }
            GLK_connection[rc1, no].Add(LK1);

            UGLink_pair LK2 = new UGLink_pair(LKx, SW, rc1, no);

            if (GLK_connection[rc2, no] == null)
            {
                GLK_connection[rc2, no] = new List <UGLink_pair>();
            }
            GLK_connection[rc2, no].Add(LK2);
        }
        public IEnumerable <UBasCov2> IEGet_BaseSet(int sz, int rnk)        //### BaseSet generator
        {
            if (GLK_UList_All.Count < sz * 2 + rnk)
            {
                yield break;
            }

            BSstatus2 = new BaseSet_Status2(sz, rnk);

            //Marking method
            // #1:Focus on the link(LK0) and follow the connecting links. A link of size(sz) is a candidate for BaseSet/CoverSet.
            //    (This alone won't make it faster.)
            // #2:Select BaseSet from the candidates and check suitability.
            //    Excludes generation G1 links.
            // #3:Also select the CoverSet from the candidates. At least common elements with baseset are required.
            //    Light selection and aptitude testing.
            //    Efficient evaluation of aptitude of baseSet is important.
            // #4:If there is no solution for the candidate starting from LK0, record LK0 in the invalid list.
            // #2':Select BaseSet from the candidates, exclude links in the invalid list.

            Bit324 invalidLink = new Bit324();

            foreach (var LK0 in GLK_UList_All)      //#1 LK0:First link
            {
                _chkX1 = false; _chkX2 = false;

                //    if( SDK_Ctrl.UGPMan.stageNo>=12 && sz>=3 ){//&& rnk==1){
                //        _chkX1=false; _chkX2=true;
                //        if(LK0.ToAppearance()=="r4#2"){
                //            WriteLine($"--->{LK0.ToAppearance()}");
                //            _chkX1=false; _chkX2=true;
                //        }
                //    }
                if (_chkX1)
                {
                    WriteLine($"\r-1- baseset sz:{sz} rnk:{rnk}  first:{LK0} -");
                }

                GLK_UList_Marked.Clear();
                QueueGlk.Clear();
                rcnGenNo         = new int[9, 81];      //### gen ###
                BasCovCandidates = new Bit324();

                #region ----- marking for LK0 -------------------------
                BasCovCandidates.BPSet(LK0.IDsq);             //1)BC_Set 候補のリスト  ## 初のリンク(LK0)の登録
                LK0._gen = 1;
                foreach (var NDx in LK0.ConnectLinks)         //LK0の他端ノードNDx に着目
                {
                    var(rc, no)      = (NDx >> 4, NDx & 0xF); // (rc,no) <-- NDx
                    rcnGenNo[no, rc] = 1;                     //### gen ###      //NDXの世代<-1    set rcnGenNo
                    QueueGlk.Enqueue(NDx);                    //Enqueue(ND1)
                    if (_chkX1)
                    {
                        WriteLine($"@{_jkc_++}      -1.5- Enqueue {rc.ToRCString()}#{no+1}");
                    }
                }

                //==== sz>=2 ====
                while (QueueGlk.Count > 0)
                {
                    var ND2 = QueueGlk.Dequeue();
                    var(rc, no) = (ND2 >> 4, ND2 & 0xF);
                    int gen = rcnGenNo[no, rc];            //### gen ###
                    if (_chkX1)
                    {
                        WriteLine($"@{_jkc_++}  -2- Dequeue {rc.ToRCString()}#{no+1}-G{gen}");
                    }

                    if (gen > sz)
                    {
                        continue;
                    }
                    foreach (var LKpair in GLK_connection[rc, no])
                    {
                        var(no2, rc2) = (LKpair.no2, LKpair.rc2);
                        var         gen2 = rcnGenNo[no2, rc2]; //### gen ###
                        UGLink_unit LKx  = LKpair.objUGL;
                        LKx._gen = gen;
                        bool hit = BasCovCandidates.IsHit(LKx.IDsq);
                        BasCovCandidates.BPSet(LKx.IDsq);   //1)BC_Set 候補のリスト ビット表現で重複を回避
                        if (_chkX1)
                        {
                            string st3 = $"@{_jkc_++}      -2.5- Link set {LKx} {(hit? "---": "New")}";
                            WriteLine(st3);
                        }

                        if (gen2 == 0)
                        {
                            rcnGenNo[no2, rc2] = gen + 1;  //### gen ###
                            if (gen < sz)
                            {
                                QueueGlk.Enqueue(LKpair.rcno);
                                if (_chkX1)
                                {
                                    string st3 = $"@{_jkc_++}         -3- Enqueue {rc2.ToRCString()}#{no2+1}-G{gen+1}";
                                    st3 += "   " + LKx.ToString();
                                    WriteLine(st3);
                                }
                            }
                        }
                    }
                }

                GLK_UList_Marked.Add(LK0);                  //First is LK0.
                BasCovCandidates.BPReset(LK0.IDsq);         //reset LK0.
                foreach (var LX in BasCovCandidates.IEGet_Index().Select(kx => GLK_UList_All[kx]))
                {
                    GLK_UList_Marked.Add(LX);
                }
                if (_chkX2)
                {
                    string stBC = $"\r@{_jkc_++} BasCovCandidates({GLK_UList_Marked.Count}) :";
                    GLK_UList_Marked.ForEach(LK => stBC += $" {LK.ToAppearance(Gen:true)}");       //#### debug print
                    WriteLine(stBC);
                }
                if (GLK_UList_Marked.Count < sz)
                {
                    continue;
                }
                #endregion ----- marking -------------------------

                #region ----- selecte -------------------------
                var         GLK_UList_Sel = new List <UGLink_unit>();
                Combination cmbBas = new Combination(GLK_UList_Marked.Count, sz);
                string      st, stw = "";
                int         nxt = int.MaxValue;             //(skip function)
                string      stT = "";
                while (cmbBas.Successor(nxt))
                {
                    nxt = int.MaxValue;
                    if (cmbBas.Index[0] != 0)
                    {
                        continue;                    //"The first link is fixed at 0!"
                    }
                    GeneralLogicGen2.ChkBas0++;      //*****

                    var   usedLKIDsq  = new Bit324();
                    var   BaseSetLst  = new List <UGLink_unit>();
                    var   HB981       = new Bit981(); //BaseSet bitPattern
                    long  RCBN_frameA = 0;
                    int[] RCB_frameB9 = new int[9];
                    foreach (var(kx, elementX) in cmbBas.IEGetIndex2())
                    {
                        nxt = kx;
                        var UGL = GLK_UList_Marked[elementX];
                        if (kx >= 1 && UGL._gen == 1)
                        {
                            goto LnxtCombination;                                   // (#2) excludes generation G1 links.
                        }
                        if (invalidLink.IsHit(UGL.IDsq))
                        {
                            goto LnxtCombination;                                   // (#2')exclude links in the invalid list.
                        }
                        usedLKIDsq.BPSet(UGL.IDsq);
                        BaseSetLst.Add(UGL);
                        foreach (var P in UGL.ConnectLinks)
                        {
                            int no2 = P & 0xF, rc2 = P >> 4;
                            if (HB981.IsHit(no2, rc2))
                            {
                                goto LnxtCombination;                               // BaseSet links do not overlap.
                            }
                            HB981.BPSet(no2, rc2);
                        }
                        long RCBN_frameB = UGL.RCBN_frameB; //bit expression of [ UC.FreeB<<27 | 1<<(UC.b+18)) | 1<<(UC.c+9) | (1<<UC.r) ]
                        int  freebX      = (int)(RCBN_frameB >> 27);
                        foreach (var no in freebX.IEGet_BtoNo())
                        {
                            RCB_frameB9[no] |= (int)(RCBN_frameB & 0x7FFFFFF);
                        }
                        RCBN_frameA |= UGL.RCBN_frameB;    //bit expression of rcb
                        if (kx > 0)
                        {
                            if (!Check_rcbnCondition(sz, rnk, elementX, RCBN_frameA))
                            {
                                goto LnxtCombination;                                                     //(### extremely efficient) ????
                            }
                        }
                    }
                    if (!Check_rcbnCondition(sz, rnk, 0, RCBN_frameA))
                    {
                        goto LnxtCombination;                                              //Evaluate BaseSet pattern. Extremely efficient.
                    }
                    if (sz >= 2)
                    {
                        BSstatus2.Prepare(usedLKIDsq, BaseSetLst, HB981, RCB_frameB9);

                        //check 421 52.1sec
                        //check 124 53.6sec

                        if (!BSstatus2.Check_4())
                        {
                            goto LnxtCombination;                           //Each element of LK0 is associated with the rest of the links.
                        }
                        if (!BSstatus2.Check_2())
                        {
                            goto LnxtCombination;                           //Each cell(A) is in a position to link with other cells.
                        }
                        if (!BSstatus2.Check_1())
                        {
                            goto LnxtCombination;                           //A and B are not linked by other link(C).
                        }
                        //  if( !BSstatus2.Check_3() ) goto LnxtCombination;  //There is a limit to the number of cells that have no links other than BaseSet.
                        //      Check_1 and _3 are almost the same evaluation. Check_3 is a heavy process.

                        //  if( !BSstatus2.Check_5() ) goto LnxtCombination;  //XXX Almost no effect. Check_1-4 has been determined.
                    }
                    var BasCov = new UBasCov2(usedLKIDsq, BaseSetLst, HB981, sz);
                    if (_chkX2)
                    {
                        string st2 = $"\r{_jkc_++} BaseSet:";
                        BaseSetLst.ForEach(P => st2 += " " + P.ToAppearance());
                        //     WriteLine(st2);
                        WriteLine($"Check_5---->{st2}");            //###################
                    }
                    yield return(BasCov);

LnxtCombination:
                    continue;
                }

                //*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*
                invalidLink.BPSet(LK0.IDsq); //#4:If there is no solution for the candidate starting from LK0, record LK0 in the invalid list.
                //*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*

                #endregion ----- selecte -------------------------
            }
            yield break;
        }
        private void _LinkSearch(bool printSW = false)
        {
            int IDx = -1;

            // *==* cell-cell link
            for (int no = 0; no < 9; no++)
            {
                for (int tfx = 0; tfx < 27; tfx++)
                {
                    int          noB  = 1 << no;
                    List <UCell> PLst = pBDL.IEGetCellInHouse(tfx, noB).ToList();
                    int          szL  = PLst.Count;
                    if (szL <= 1)
                    {
                        continue;
                    }
                    int SW = (szL == 2)? 0: 1;
                    IDx++;
                    var LK1 = new UGLink_unit(IDx, SW, tfx, no, PLst);
                    GLK_UList_All.Add(LK1);
                    Combination cmb = new Combination(szL, 2);
                    while (cmb.Successor())
                    {
                        UCell UC1 = PLst[cmb.Index[0]], UC2 = PLst[cmb.Index[1]];
                        __SetGLinkLstSet(LK1, SW, tfx, no, UC1, UC2);
                    }
                }
            }

            // *==* in-cell link
            foreach (var P in pBDL.Where(p => p.No == 0))
            {
                int   rc    = P.rc;
                int[] noLst = P.FreeB.IEGet_BtoNo().ToArray();
                int   szL   = noLst.Length;
                if (szL <= 1)
                {
                    continue;
                }
                int SW = (szL == 2)? 0: 1;
                IDx++;
                var LK2 = new UGLink_unit(IDx, SW, rc, P.FreeB);
                GLK_UList_All.Add(LK2);

                Combination cmb = new Combination(szL, 2);
                while (cmb.Successor())
                {
                    int no1 = noLst[cmb.Index[0]], no2 = noLst[cmb.Index[1]];
                    __SetGLinkLstSet(LK2, SW, rc, no1, no2);
                }
            }

            if (printSW)
            {
                WriteLine($"============================ stage:{stageNo} GLK_UList_All");
                foreach (var P in GLK_UList_All)
                {
                    WriteLine(P);
                }
                WriteLine($"============================ stage:{stageNo} GLK_connection");
                foreach (var rc in Enumerable.Range(0, 81))
                {
                    foreach (var no in Enumerable.Range(0, 9))
                    {
                        if (GLK_connection[rc, no] != null)
                        {
                            GLK_connection[rc, no].ForEach(P => WriteLine(P.ToString_rcno(rc, no)));
                        }
                    }
                }
            }
        }