prologの事実みたいなことをやりたいFact

prolog知らない人のために説明

例えば

(1,3,5),(2,4,6),(1,4,9)

みたいなのがあったとして

(1,?,?)

と聞くと

(3,5),(4,9)

と返してくれる。そんなのが欲しかったんだ

 

class Fact
{
public:
    typedef boost::optional<T> Arg;
    typedef std::vector<T> Result;
    typedef std::vector<std::vector<T>> Results;
    typedef boost::optional<Results> result_type;
    template<class CONTAINER>
    result_type operator()(const CONTAINER&container)const
    {
        return operator()(container.begin(),container.end());
    }

    template<class Iter>
    result_type operator()(const Iter&begin,const Iter&end)const
    {
        std::set<size_t> pushs;                //返り値になるもの
        typedef std::map<size_t,Iter> Args;
        Args args;                            //引数的なもの
        size_t i=0;
        for(auto it=begin;it!=end;++it,++i)
        {
            if(*it)
                args.insert(Args::value_type(i,it));
            else
                pushs.insert(i);
        }
        const size_t len=std::distance(begin,end);
        if(pushs.empty())
        {
            std::vector<T> temp;
            for(auto it=begin;it!=end;++it)
                temp.push_back(**it);
            if(std::find(data.begin(),data.end(),temp)==data.end())
                return result_type();
            else
                return Results();
        }
        Results result;
       
       
        std::function<bool(const ELEM&)> check=[&](const ELEM&x)
        {
            return len==x.size()&&std::all_of(args.begin(),args.end(),[&](const Args::value_type&y)
                {
                    return x.at(y.first) == *(y.second);
                });
        };
        std::function<Result(const ELEM&)> Make=[&](const ELEM&x)
        {
            Result temp;
            for(auto i:pushs)
                temp.push_back(x.at(i));
            return temp;
        };
        for(auto&x:data)
        {
            if(check(x))
                result.push_back(Make(x));
        }
        if(result.empty())return result_type();
        return result;
    }

    template<class CONTAINER>
    void Set(const CONTAINER&container)
    {
        Set(container.begin(),container.end());
    }

    template<class Iter>
    void Set(const Iter&begin,const Iter&end)
    {
        data.push_back(ELEM(begin,end));
    }
private:
    typedef std::vector<T> ELEM;
    std::vector<ELEM> data;
};

 

//main

    using boost::assign::list_of;
    Fact<int> f;
    typedef Fact<int>::Arg Arg;

    f.Set(list_of(3)(1)(0)(1));//事実を入れている
    f.Set(list_of(3)(2)(2)(3));
    f.Set(list_of(3)(1)(9)(1));
   
    auto r=f(list_of<Arg>(3)(1)()(3));//条件

    output(r);//出力してます

出力

false

条件を(3)()()(1)にすると

true 

1,0

1,9

 となる