public bool cubre(Literal condicion, Dictionary<string, List<string> > valores_vars)
        {
            List<string>[] atributos_a_buscar = new List<string>[condicion.nAtt];

            for(int i = 0; i<condicion.nAtt; i++)
            {
                if (valores_vars.ContainsKey(condicion.Atributos[i]))
                    atributos_a_buscar[i] = valores_vars[condicion.Atributos[i]];
                else
                    atributos_a_buscar[i] = new List<string> { "?" };
            }

            var posibles_valores = (from conocimiento in baseConocimiento
                                    where (conocimiento.Nombre == condicion.Nombre)
                                        && completa(conocimiento, atributos_a_buscar)
                                    select conocimiento.Atributos);
            if (posibles_valores.Any())
            {
                for(int i = 0; i<condicion.nAtt; i++)
                {
                    valores_vars[condicion.Atributos[i]] = (from valor in posibles_valores
                                                            select valor[i]).Distinct().ToList();
                }

                return true;
            }
            else
                return false;
        }
        public Algoritmo( string path, string pred_obj)
        {
            predicados = new HashSet<Literal>();
            dominio = new HashSet<string>();
            baseConocimiento = new List<Literal>();
            conocimientoPos = new List<Literal>();
            conocimientoNeg = new List<Literal>();
            objetivo = pred_obj;
            var file = (from lines in File.ReadAllLines(@path)
                        let line = lines.Split(new[] { "(" }, StringSplitOptions.RemoveEmptyEntries)
                        select new
                        {
                            predicado = line[0],
                            atributos = line[1].Split(new[] { ", " }, StringSplitOptions.RemoveEmptyEntries)
                        }
                        );
            foreach (var lit in file)
            {
                int natt = lit.atributos.Count();
                Literal nuevo = new Literal(lit.predicado, natt);
                predicados.Add(nuevo.Clone()); //para tener la cardinalidad tb
                string[] att = lit.atributos;
                att[natt - 1] = att[natt - 1].Remove(att[natt - 1].Count() - 1);
                nuevo.Atributos = att;

                dominio.UnionWith(att);

                if (lit.predicado == pred_obj)
                    conocimientoPos.Add(nuevo);
                else
                {
                    baseConocimiento.Add(nuevo);
                    //predicados.Add(lit.predicado); //Para recursivo poner fuera del else
                }
            }
            predicados.RemoveWhere(T => T.Nombre == objetivo);
            int n_att = conocimientoPos[0].nAtt;
            foreach (var litNeg in dominio.Repetitions(n_att))
            {
                Literal nuevo = new Literal(pred_obj, n_att);
                nuevo.Atributos = litNeg;
                conocimientoNeg.Add(nuevo);
            }
            conocimientoNeg.RemoveAll(T => conocimientoPos.Contains(T));
        }
 public Regla(Regla cpy)
 {
     predicado = cpy.predicado;
     precondiciones = new List<Literal>(cpy.precondiciones.Select(x => x.Clone()));
 }
 public Regla(Literal pred)
 {
     predicado = pred;
     precondiciones = new List<Literal>();
 }
 private double ganancia(Literal candidato, Regla nuevaRegla, float p0, float n0)
 {
     /*
      * p0 = numero de ej+ cubiertos por R
      * n0 = numero de ej- cubiertos por R
      * p1 = numero de ej+ cubiertos por R'
      * n1 = numero de ej- cubiertos por R'
      * t = numero ej+ cuebiertos en R tb cubiertos en R'
      *
      */
     Regla reglaConCandidato = new Regla(nuevaRegla);
     reglaConCandidato.Precondiciones = new List<Literal> { candidato };
     float p1 = (from positivo in conocimientoPos
             where cubre(reglaConCandidato, positivo)
             select positivo).Count(),
         n1 = (from negativo in conocimientoNeg
             where cubre(reglaConCandidato, negativo)
             select negativo).Count(),
         t = (from positivo in conocimientoPos
             where cubre(nuevaRegla, positivo) && cubre(reglaConCandidato, positivo)
             select positivo).Count();
     if (t == 0)
         return 0;
     else
         return  t*( Math.Log(p1/(p1+n1)) - Math.Log(p0 / (p0 + n0)) );
 }
        private bool cubre(Regla nuevaRegla, Literal faltaAceptar)
        {
            Dictionary<string, List<string> > valores_vars = new Dictionary<string, List<string> >();

            for(int i = 0; i<nuevaRegla.Predicado.nAtt; i++)
            {
                valores_vars.Add(nuevaRegla.Predicado.Atributos[i],
                                 new List<string> { faltaAceptar.Atributos[i] });
            }
            foreach( var condicion in nuevaRegla.Precondiciones)
            {
                if (!cubre(condicion, valores_vars))
                    return false;
            }

            return true;
        }
        private bool completa(Literal conocimiento, List<string>[] atributos_a_buscar)
        {
            bool esCompletado = true;
            int i = 0;

            while( i<conocimiento.nAtt && esCompletado)
            {
                esCompletado = atributos_a_buscar[i].Contains("?")
                                || atributos_a_buscar[i].Contains(conocimiento.Atributos[i]);
                i++;
            }

            return esCompletado;
        }
        public List<Regla> Foil(bool recursive)
        {
            List<Regla> reglasAprendidas = new List<Regla>();
            bool añadir = recursive;

            while( conocimientoPos.Any() )
            {
                int nAtt_objetivo = conocimientoPos[0].nAtt;
                Literal pred_objetivo = new Literal(objetivo, nAtt_objetivo);
                int ultima_var = nAtt_objetivo;
                string[] atributos = new string[nAtt_objetivo];
                HashSet<string> usados = new HashSet<string>();
                for (int i = 0; i < nAtt_objetivo; i++)
                {
                    atributos[i] = ""+i;
                    usados.Add(""+i);
                }
                pred_objetivo.Atributos = atributos;
                Regla nuevaRegla = new Regla(pred_objetivo);
                List<Literal> negativosAceptados = conocimientoNeg;

                while( negativosAceptados.Any() )
                {
                    List<Literal> candidatos = generarCandidatos(predicados, usados);
                    float p0 = (from positivo in conocimientoPos
                              where cubre(nuevaRegla, positivo)
                              select positivo).Count(),
                         n0 = (from negativo in conocimientoNeg
                              where cubre(nuevaRegla, negativo)
                              select negativo).Count();
                    double mejorGanancia = ganancia(candidatos[0], nuevaRegla, p0, n0);
                    Literal mejorLiteral = candidatos[0];
                    candidatos.RemoveAt(0);
                    foreach(var candidato in candidatos)
                    {
                        double gan = ganancia(candidato, nuevaRegla, p0, n0);
                        Console.WriteLine(candidato + " -> " + gan);
                        if(gan > mejorGanancia)
                        {
                            mejorGanancia = gan;
                            mejorLiteral = candidato;
                        }
                    }
                    nuevaRegla.Precondiciones = new List<Literal> { mejorLiteral };
                    foreach( var variable in mejorLiteral.Atributos )
                    {
                         usados.Add(variable);
                    }
                    negativosAceptados = (from aceptados in negativosAceptados
                                          where cubre(nuevaRegla, aceptados)
                                          select aceptados).ToList();

                    if (añadir)
                    {
                        predicados.Add(new Literal(objetivo, conocimientoPos[0].nAtt));
                        añadir = false;
                    }
                }
                reglasAprendidas.Add(nuevaRegla);

                conocimientoPos = (from faltaAceptar in conocimientoPos
                                   where !cubre(nuevaRegla, faltaAceptar)
                                   select faltaAceptar).ToList();
                Console.WriteLine(nuevaRegla + "\n \t\t -> faltan = " + conocimientoPos.Count());
                predicados.RemoveWhere(T => T.Nombre == objetivo);
                añadir = recursive;
            }

            return reglasAprendidas;
        }