//original recursive algorithm that attempts to eliminate half candidates with each question func askQuestions(u []*rx.BitSet, h []rx.DFAexample, e []*RegEx, alive *rx.BitSet, track int, iter int, answers *rx.BitSet, qns []string, cand []*rx.DFA) ([]*rx.BitSet, []rx.DFAexample, *rx.BitSet, []string) { t := make([]*rx.BitSet, 0, len(u)) k := make([]rx.DFAexample, 0, len(h)) //none left alive, means there is no match in the corpus if alive.Count() == 0 { fmt.Println("No reg ex in our library matches your query.") fmt.Println("answers after iter = ", iter, " ", answers.String()) return t, k, answers, qns } //if there was at least 1 yes answer and only 1 remaining expr alive, it must be accepted by the target if track >= 1 { if alive.Count() == 1 { if findQn(alive, h) != "" { answers.Set(iter) qns = append(qns, findQn(alive, h)) } fmt.Println("answers after iter = ", iter, " ", answers.String()) return t, k, answers, qns } } //if there were 0 yes answers and there is 1 remaining, must ask again or return no match if track == 0 && alive.Count() == 1 { if len(u) == 0 { fmt.Println("No reg ex in our library matches your query.") fmt.Println("answers after iter = ", iter, " ", answers.String()) return t, k, answers, qns } else { goto askAgain } askAgain: //ask last question qns = append(qns, h[0].Example) fmt.Println("Does your language accept this word: ", h[0].Example) var input1 string _, e1 := fmt.Scan(&input1) if e1 != nil { fmt.Printf("err = %#v\n", e1) os.Exit(2) } if input1 == "Yes" || input1 == "y" || input1 == "Y" || input1 == "yes" { track++ answers.Set(iter) fmt.Println("answers after iter = ", iter, " ", answers.String()) return t, k, answers, qns } else if input1 == "No" || input1 == "N" || input1 == "n" || input1 == "no" { fmt.Println("No reg ex in our library matches your query.") fmt.Println("answers after iter = ", iter, " ", answers.String()) return t, k, answers, qns } else { fmt.Println("That is not a valid expression, please try again.") goto askAgain } } //if 0 yes answers, and no more questions, no match found if track == 0 && len(u) == 0 { fmt.Println("No reg ex in our library matches your query.") return t, k, answers, qns } //if no more questions but more than 1 candidate, find the next question if len(u) == 0 && alive.Count() > 1 { qns = append(qns, findQn(alive, h)) return t, k, answers, qns } //Iterate through u to find the rx.BitSet with numleft/2 bits set to 1 i := 0 n := float64(alive.Count() / 2) size := math.Floor(n) //if small enough set, take the cieling if alive.Count() < 4 && math.Mod(float64(alive.Count()), 2) == 1 { size = size + 1 } cur := u[i].Count() c := float64(cur) hM := float64(math.Abs(c - size)) nextQn := u[i] word := h[i].Example examInt := i //find the region that is the intersection of n/2 regexs (or closest to n/2) for i := 0; i < len(u); i++ { c = float64(u[i].Count()) if math.Abs(c-size) == 0 { nextQn = u[i] word = h[i].Example examInt = i break } else if math.Abs(c-size) < hM { hM = math.Abs(c - size) nextQn = u[i] word = h[i].Example examInt = i } else { /*do nothing*/ } } qns = append(qns, word) //append question to list rate := rateQns(qns, cand) //rate the questions for i := 0; i < len(rate); i++ { fmt.Println(rate[i], " dfas accepted this word ", qns[i]) } //ask if the best question word is accepted fmt.Println("Does your language accept this word: ", word) begin: var input string _, e1 := fmt.Scan(&input) if e1 != nil { fmt.Printf("err = %#v\n", e1) os.Exit(2) } //Refine the candidate set based on the answer if input == "Yes" || input == "y" || input == "Y" || input == "yes" { track++ if nextQn.Count() == 1 { t = append(t, nextQn) k = append(k, h[examInt]) answers.Set(iter) fmt.Println("answers after iter = ", iter, " ", answers.String()) return t, k, answers, qns } answers.Set(iter) alive = alive.And(nextQn) for i := 0; i < len(u); i++ { if !((nextQn.And(u[i])).IsEmpty()) && !(nextQn.Equals(u[i])) { t = append(t, u[i]) k = append(k, h[i]) } } fmt.Println("alive =", alive.String()) } else if input == "No" || input == "N" || input == "n" || input == "no" { bs := new(rx.BitSet) for i := 0; i < len(e); i++ { if !(nextQn.Test(e[i].Index)) { bs.Set(e[i].Index) } } alive = bs.And(alive) for i := 0; i < len(u); i++ { if !((bs.And(u[i])).IsEmpty()) { t = append(t, u[i]) k = append(k, h[i]) } } fmt.Println("alive = ", alive.String()) } else { fmt.Println("That is not a valid expression, please try again.") fmt.Println("Does your language accept this word: ", word) goto begin } fmt.Println("answers after iter = ", iter, " ", answers.String()) iter++ //recursive call on the new candidate set return askQuestions(t, k, e, alive, track, iter, answers, qns, cand) }