Angel "Java" Lopez

NET, Java, PHP y Desarrollo de Software

This Blog

Syndication

Search

Tags

Community

Email Notifications

Archives

.NET

ASP.NET

Windows Form

VB.NET

C#

Sitios

Blogs

January 2011 - Posts

Escribiendo un Intérprete en .NET (Parte 9)

Anterior Post
Primer Post de la Serie

Esta vez, quiero agregar una pieza que falta: un composite command. El intérprete necesita una manera de ejecutar una lista de comandos, en cualquier lugar donde haya un comando: en un if/then, en el if/else, en el while, etc… Primero, escribí un test (esta version de abajo no es la versión inicial, es la final actual):

        [TestMethod]
        public void CreateAndEvaluateCompositeCommand()
        {
            BindingEnvironment environment = new BindingEnvironment();
            environment.SetValue("a", 0);
            ICommand add1 = this.MakeAddCommand("a", "a", 1);
            ICommand add2 = this.MakeAddCommand("a", "a", 2);
            CompositeCommand cmd = new CompositeCommand(new ICommand[] { add1, add2 });
            Assert.IsNotNull(cmd.Commands);
            Assert.AreEqual(2, cmd.Commands.Count);
            Assert.AreEqual(add1, cmd.Commands.First());
            Assert.AreEqual(add2, cmd.Commands.Skip(1).First());
            cmd.Execute(environment);
            Assert.AreEqual(3, environment.GetValue("a"));
        }
        private ICommand MakeAddCommand(string target, string source, int number)
        {
            IExpression add = new BinaryArithmeticBLOCKED EXPRESSION;
        }

El código mostrado es la versión ACTUAL. Durante el desarrollo, y usando TDD, escribí el código de a pasos cortos,  y también apliqué refactoring. Pero la lección es: usar los tests para guiar nuestro desarrollo.

Todos los tests en verde:

Buen code coverage:

Pueden bajar la versión actual desde from InterpreterStep09.zip. Si quieren ver todos los steps, sigo enviando mi código a trunk/Interpreter en mi Google Code Project AjCodeKatas.

Próximos pasos: comando foreach, comando for, declaración de funciones, etc…

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Fri, Jan 28 2011 10:00 by lopez | 3 comment(s)

Escribiendo un Intérprete in .NET (Part 8)

Vuelvo a escribir sobre el tema: programar un intérprete, usando C# y algunas ideas de TDD. En este paso, agrego un nuevo ICommand, el WhileCommand:

Pueden bajarse la versión de este paso desde InterpreterStep08.zip. Si quieren ver todos los pasos, sigo manteniendo el códicon en trunk/Interpreter en mi Google Code Project AjCodeKatas.

El código de WhileCommand es simple:

    public class WhileCommand : ICommand
    {
        private IExpression condition;
        private ICommand command;
        public WhileCommand(IExpression condition, ICommand command)
        {
            this.condition = condition;
            this.command = command;
        }
        public IExpression Condition { get { return this.condition; } }
        public ICommand Command { get { return this.command; } }
        public void Execute(BindingEnvironment environment)
        {
            while (BooleanPredicates.IsTrue(this.condition.Evaluate(environment)))
                this.command.Execute(environment);
        }
    }

Noten que tengo ahora un nuevo BooleanPredicates. Nació de haber refctorizado el código anterior que usé en la implementación de IfCommand. Escribí en el anterior post sobre mis intenciones de hacer ese refactor. Usando TDD, escribí los tests de la nueva clase, ejemplo:

        [TestMethod]
        public void IsFalse()
        {
            Assert.IsTrue(BooleanPredicates.IsFalse(null));
            Assert.IsTrue(BooleanPredicates.IsFalse(string.Empty));
            Assert.IsTrue(BooleanPredicates.IsFalse(0));
            Assert.IsTrue(BooleanPredicates.IsFalse((short)0));
            Assert.IsTrue(BooleanPredicates.IsFalse((long)0));
            Assert.IsTrue(BooleanPredicates.IsFalse(0.0));
            Assert.IsTrue(BooleanPredicates.IsFalse((float)0.0));
            Assert.IsFalse(BooleanPredicates.IsFalse(new object()));
            Assert.IsFalse(BooleanPredicates.IsFalse("foo"));
            Assert.IsFalse(BooleanPredicates.IsFalse(1));
            Assert.IsFalse(BooleanPredicates.IsFalse((short)2));
            Assert.IsFalse(BooleanPredicates.IsFalse((long)3));
            Assert.IsFalse(BooleanPredicates.IsFalse(4.0));
            Assert.IsFalse(BooleanPredicates.IsFalse((float)5.0));
        }

Vean: el test es una especie de especificación escrita en código, que contesta: ¿Qué es lo que considero como false en mi intérprete? Luego de tener el test en verde, pude agregar su llamada en el IfCommand (que YA estaba escrito) y ver de correr los tests de ese comando, para ver que todo siguiera funcionando.

El nuevo comando WhileCommand nació de haberlo testeado, ejemplo:

        [TestMethod]
        public void EvaluateWhileCommandUsingDecrement()
        {
            BindingEnvironment environment = new BindingEnvironment();
            environment.SetValue("a", 2);
            IExpression condition = new VariableBLOCKED EXPRESSION;
        }

Podría haber agregado más tests, como qué pasa si al WhileCommand le entrego una condición null, pero, por ahora, el nuevo comando goza de buena salud. Todos los tess siguen en verde:

Buen code coverage:

Próximos pasos: comandos composite, comandos for/foreach, declaración de funciones…

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Thu, Jan 20 2011 10:27 by lopez | 2 comment(s)

NHibernate 3 (Parte 1) Un mapeo simple

Siguiente post

Hace año y medio escribí un ejemplo en NHibernate 2.0:

First NHibernate 2.x Example

Este año que recién comienza, quiero explorar el nuevo release NHibernate 3.0 con ejemplos. Pueden bajar la versión actual de este ORM para .NET desde:

http://sourceforge.net/projects/nhibernate/files/

Uso NHibernate-3.0.0.GA-bin.zip para la solución:

Mantengo este ejempo en mi proyecto AjCodeKatas, en el directorio trunk/NHibernate/SimpleMapping. El código no incluye las librerías de NHibernate, así que tienen que agregar las referencias a los proyectos. Yo agregué al proyecto SimpleMapping.Console todas las .dll de los directorios de NHibernate NHibernate Required_Bins y Required_For_LazyLoading\Castle.

Si son perezosos, como yo ;-), pueden directamente bajarse el ejemplo completo con las librerías incluidas desde mi Skydrive: NHibernate3SimpleMapping.zip.

Noten que creé una solución con un Solution folder Schemas, en el que agregué los archivos de esquemas .xsd que encontré en el directorio Required_Bins dentro de la distribución binaria de NHibernate. Esto permite que puedan usar Intellisense cuando escriban algunos archivos que NHibernate necesita.

El proyecto SimpleMapping.Domain NO referencia a NHibernate (una prueba de la independencia de nuestro dominio de la persistencia) y contiene una sola clase:

    public class Customer
    {
        public virtual Guid Id { get; set; }
        public virtual string Name { get; set; }
        public virtual string Address { get; set; }
        public virtual string Notes { get; set; }
    }

Escribí un app.config en la aplicación de consola:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section
    name="hibernate-configuration"
    type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"
/>
  </configSections>
  <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <session-factory>
      <property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
      <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
      <property name="connection.connection_string">Data Source=.\SQLEXPRESS;Initial Catalog=NHibernate3SimpleMapping;Integrated Security=True</property>
      <property name="proxyfactory.factory_class">
        NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle
      </property>
      <mapping assembly="SimpleMapping.Console" />
    </session-factory>
  </hibernate-configuration>
</configuration>

Tenemos que ir estudiando los parámetros que necesita NHibernate. Pero a simple vista: aparece el string de conexión, y el dialecto. Vamos a tener que estudiar qué es esos del dialecto: un adelanto rápido, es la clase de NHibernate que sabe cómo generar comandos SQL para la base de datos que estemos usando. NHibernate puede acceder a otros tipos de bases de datos, no sólo a SQL Server, y el dialecto es la forma que tiene de poder generar comandos SQL especiales para cada base de datos (por ejemplo, el manejo de recuperación autonuméricos).

Escribí un archivo Customer.hbm.xml. Atención: Lo marqué como Embedded Resources en su ventana de propiedades. No se olviden de este paso: en este ejemplo, le estamos diciendo en el parámetro mapping de la configuración de más arriba, que todos los mapeos están incluidos en el assembly SimpleMapping.Console. Vean que las clases pueden estar definidas en un proyecto, y los mapeos en otro. Este es el contenido del Customer.hbm.xml:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="SimpleMapping.Domain"
namespace="SimpleMapping.Domain">
  <class name="Customer" table="Customers">
    <id name="Id">
      <generator class="guid.comb" />
    </id>
    <property name="Name" not-null="true" />
    <property name="Address" />
    <property name="Notes" />
  </class>
</hibernate-mapping>

Para crear la base de datos, pueden ejecutar Sql\ExecuteAll.cmd (ver Readme.txt para más detalles).

El programa de consola solamente crea un cliente, lo graba en la base, y recupera todos los clientes existentes:

    ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
    using (ISession session = sessionFactory.OpenSession())
    {
        using (ITransaction tx = session.BeginTransaction())
        {
            Customer customer1 = new Customer();
            customer1.Name = "Customer 1";
            customer1.Address = "Address 1";
            customer1.Notes = "Notes 1";
            session.Save(customer1);
            IQuery query = session.CreateQuery("from Customer");
    
            foreach (Customer c in query.List<Customer>())
                System.Console.WriteLine(string.Format("Customer {0}", c.Name));
            tx.Commit();
            session.Close();
        }
    }

(Disculpen, no estoy muy creativo para los los valores de las propiedades ;-)

Hay varios detalles para discutir: ¿Qué es eso del Castle bytecode? ¿Para qué sirve cada propiedad que pusimos en la configuración? ¿Qué es una session? ¿Y una transacción? ¿Qué es un Id? ¿Qué es un guid.comb? ¿Qué alternativas tenemos a haber puesto ese valor? ¿Cómo mapear una propiedad de otro tipo, como Currency, DateTime, etc..?.

¿Y qué pasa si necesitamos más clases? ¿Y el manejo de la herencia? ¿Y cómo tratamos las relaciones uno a varios? Y muchos otros puntos, todo a explorar en los siguientes post de la serie.

Mientras, algunos recursos:

Online NHibernate Documentation
NHibernate available resources
SourceForge project

Libro: Jason Dentler’s NHibernate 3.0 Cookbook

http://delicious.com/ajlopez/nhibernate+tutorial

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Tue, Jan 18 2011 10:05 by lopez | 3 comment(s)

Filed under: , ,

ALT.NET Hispano VAN Programando en Azure

Gracias a la gente de la comunidad ALT.NET Hispano, el próximo sábado 29 de Enero, a las 18hs (GMT) (15hs acá en Argentina), participaré de una VAN (desconferencia virtual), tratando el de Programar en Azure.

Presentaré los temas:

- Conceptos de Windows Azure y Cloud Computing

- Web Roles

- Worker Roles

- Azure Storage: Blobs, Queues, Tables

- Patrones

- Ejemplos

Tratando de dar una visión de cómo se puede programar y aprovechar la plataforma Azure para nuestras aplicaciones en la nube. Ya estoy publicando código y ejemplos en este blog. Lo que presente quedará en la página de la comunidad y en este blog.

Mis enlaces sobre el tema:

http://delicious.com/ajlopez/azure

Para participar, entrar al enlace http://snipr.com/virtualaltnet

Recuerdo lo que el Microsoft MVP @jorgegamba escribió sobre estas reuniones:

Hay que aclarar que no se requiere ningún tipo de registro, simplemente acudir el día y la hora indicados a la dirección Web http://snipr.com/virtualaltnet, eso sí, deberán tener instalado el programa cliente de Live Meeting; hay más instrucciones sobre cómo hacer esto y otras indicaciones en la página Descripción de Reuniones.

Para los que no puedan asistir, quedará publicado un video en el sitio de la comunidad.

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Fri, Jan 7 2011 11:03 by lopez | 2 comment(s)

Elementos abstractos en AjGroups

He escrito sobre mi librería de grupos finitos AjGroups en mis anteriores posts:

Presenting AjGroups: Finite Groups Library
Presentando AjGroups: una Librería de Grupos Finitos
Permutations in AjGroups
Permutaciones en AjGroups

Ahora, quiero presentar otra de las implementaciones de un grupo finito que usé la solución: una basada, no en permutaciones explícitas, sino en elementos abstractos.

Un elemento abstracto es identificado por un nombre:

Los nombres pueden ser letras: a, b, c, …. Por convención, el elemento e es la identidad. Entonces

a * e = e * a

para cualquier a. Pero, ¿cuál es el resultado de a * b para a, b cualesquiera en un grupo? Los resultados están en un OperationTable:

El OperationTable mantiene una lista de elementos y una matriz. Cada celda de la matriz tiene el resultado de dos elementos:

public void SetValue(IElement left, IElement right, IElement value)
{
    this.SetValue(elements.IndexOf(left), elements.IndexOf(right), value);
}
public IElement GetValue(IElement left, IElement right)
{
    return this.GetValue(elements.IndexOf(left), elements.IndexOf(right));
}
internal void SetValue(int leftpos, int rightpos, IElement value)
{
    cells[leftpos, rightpos] = value;
}
internal IElement GetValue(int leftpost, int rightpos)
{
    return cells[leftpost, rightpos];
}
		

La OperationTable puede ser armada calculando sobre permutaciones (elementos concretos). Un test:

[TestMethod]
public void CalculateSymmetricGroupTable()
{
    IGroup group = new SymmetricGroup(3);
    OperationTable table = new OperationTable(group.Elements);
    table.Calculate();
    foreach (IElement left in group.Elements)
        foreach (IElement right in group.Elements)
            Assert.AreEqual(left.Multiply(right), table.GetValue(left, right));
}

Pero esa no era mi idea: quiero usar OperationTable con elementos abstractos, y construir a mano o por algún cálculo (más detalles abajo) la matriz con los resultados de las multiplicaciones.

La OperationTable tiene métodos como: .HasIdentity, .IsAssociative, .IsConmutative, para determinar sus propiedades. No toda tabla será compatible con los axiomas de grupo. Un test:

[TestMethod]
public void SymmetricGroupThreeOperationIsAssociative()
{
    OperationTable table = new OperationTable((new SymmetricGroup(3)).Elements);
    table.Calculate();
    Assert.IsTrue(table.IsAssociative);
}

Notablemente, la OperationTable puede estar incompleta: puede que algunas celdas esté indefinidas. El método .IsClosed retorna true si la matriz de multiplicación está completamente definida, y cada resultado de la multiplicación de dos elementos cualquiera está completamente definida.

La OperationTable puede ser construida a mano. Por ejemplo, la tabla:

se construye y prueba en este test:

[TestMethod]
public void CreateWithNamedIdentityAndOneElement()
{
    NamedElement identity = new NamedElement('e');
    NamedElement aelement = new NamedElement('a');
    OperationTable table = new OperationTable(new List<IElement>() { identity , aelement}, true);
    identity.OperationTable = table;
    aelement.OperationTable = table;
    table.SetValue(aelement, aelement, identity);
    Assert.IsTrue(table.HasIdentity);
    Assert.IsTrue(table.IsAssociative);
    Assert.IsTrue(table.IsClosed);
    Assert.IsTrue(table.IsCommutative);
    Assert.AreEqual(2, table.Elements.Count);
    Assert.AreEqual(identity, table.GetValue(identity, identity));
    Assert.AreEqual(aelement, table.GetValue(aelement, identity));
    Assert.AreEqual(aelement, table.GetValue(identity, aelement));
    Assert.AreEqual(identity, table.GetValue(aelement, aelement));
    Assert.AreEqual(1, identity.Order);
    Assert.AreEqual(2, aelement.Order);
}

Pero mi método preferido en OperationTable es el método .GetSolutions(). Dada una OperationTable incompleta, retorna una lista de OperationTables completas (con todas las multiplicaciones definidas) que son compatibles con los axiomas de grupo. Sea esta tabla inicial incompleta:

Aplicando .GetSolutions() a esta tabla de operaciones retorna una lista con un solo elemento (la tabla del único grupo finito de 3 elementos):

Noten: cada fila y cada columna ES una permutación de los elementos originales. Esa regla es necesaria según los axiomas de grupo.

Un test:

[TestMethod]
public void GetGroupsOfOrderThree()
{
    NamedElement identity = new NamedElement('e');
    NamedElement aelement = new NamedElement('a');
    NamedElement belement = new NamedElement('b');
    OperationTable table = new OperationTable(new List<IElement>() { identity, aelement, belement }, true);
    IList<OperationTable> solutions = table.GetSolutions().ToList();
    Assert.IsNotNull(solutions);
    Assert.AreEqual(1, solutions.Count);
    Assert.IsTrue(solutions[0].IsClosed);
}

Pero una OperationTable no es un IGroup. Hay otra clase TableGroup:

Su constructor recibe una OperationTable: clona sus elementos (que deben ser abstracots), clona su OperationTable, para armar un nuevo grupo abstracto.

Las tablas retornadas por .GetSolutions() no son todos diferentes según isomorfismos. Tengo un método, internamente usado por los tests, que retorna todos los grupos esencialmente distintos de orden n, partiendo en cada caso de una tabla incompleta y aplicándole .GetSolutions() y filtro por isomorfismo:

private static IList<IGroup> GetGroupsOfOrder(int order)
{
    IList<IElement> elements = new List<IElement>();
    for (int k = 0; k < order; k++)
        elements.Add(new NamedElement(k));
    OperationTable table = new OperationTable(elements, true);
    IList<OperationTable> solutions = table.GetSolutions().ToList();
    foreach (OperationTable solution in solutions)
    {
        Assert.IsTrue(solution.HasIdentity);
        Assert.IsTrue(solution.IsAssociative);
        Assert.IsTrue(solution.IsClosed);
    }
    IList<IGroup> groups = new List<IGroup>();
    foreach (OperationTable ot in solutions)
        groups.Add(new TableGroup(ot));
    IList<IGroup> dgroups = GroupUtilities.GetNonIsomorphic(groups);
    return dgroups;
}

El método .GetSolutions() se basa en el uso del método .GetCompatibleTable(a,b,c) que trata de agregar la ecuación:

a * b = c

a una OperationTable, sin romper los axiomas de grupo. Si una tabla compatible existe, el método la retorna, sin alterar la original. Si no existe, retorna null.

Todo esto fue construido usando Test-Driven Development (TDD). Notablemente, el diseño original no incluía elementos abstractos: estaba basado totalmente en permutaciones. Próximo post: describir cómo TDD “salvó mi día”, cuando tuve que agregar elementos abstractos.

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Thu, Jan 6 2011 9:32 by lopez | with no comments

Permutaciones en AjGroups

En mi anterior post presenté a AjGroups, una librería de clases escrita en C# que implementa conceptos y operaciones de grupos finitos. El código fuente está en mi AjCodeKata Google Project, en trunk/AjGroups.

En este post, quisiera explicar una de las implementaciones que están dentro de AjGroups: grupos basados en permutaciones.

Una permutación es una aplicación biyectiva de un conjunto S a S. Sea

S = { 0, 1, 2, 3, 4 }

Entonces, un ejemplo de permutación es:

i(0)=0, i(1)=1, i(2)=2, i(3)=3, i(4)=4

Es la permutación identidad. Otro ejemplo:

s(0)=1, s(1)=0, s(2)=2, s(3)=3, s(4)=4

Esta es un “swap”, un intercambio de los dos primeros elementos. Una permutación “rotación”:

r(0)=1, r(1)=2, r(2)=3, r(3)=4, r(4)=0

Las permutaciones pueden combinarse para dar otras permutaciones, r*s:

(r*s)(n) = r(s(n))

Las permutaciones de S son los elementos de un grupo que usa la operación *. AjGroups implementa una permutación usando la clase Element:

    public class Element : AjGroups.IElement
    {
        private byte[] values;
        public Element(params byte[] values)
        {
//....
    }

La permutación se representa en un arreglo de bytes, donde values[k] es el resultado de f(k), siendo f la permutación representada por el Element.

Element.Multiply(Element element) implementa la multiplicación:

       public Element Multiply(Element element)
        {
            int k;
            int length1 = this.values.Length;
            int length2 = element.values.Length;
            int newlength = Math.Max(length1, length2);
            byte[] newvalues = new byte[newlength];
            for (k = 0; k < newlength; k++)
            {
                if (k >= length2)
                {
                    newvalues[k] = this.values[k];
                }
                else if (element.values[k] >= length1)
                {
                    newvalues[k] = element.values[k];
                }
                else
                {
                    newvalues[k] = this.values[element.values[k]];
                }
            }
            return new Element(newvalues);
        }

Noten que el método soporta la multiplicación de permutaciones de diferentes tamaños.

Element.CreateIdentity genera un elemento identidad, de tamaño n.

Creando un swap de las dos primeras posiciones:

        public static Element CreateSwap(int size) 
        {
            Element element = CreateIdentity(size);
            element.values[0] = 1;
            element.values[1] = 0;
            return element;
        }

Creando un intercambio en una posición:

        public static Element CreateSwap(int size, int position)
        {
            Element element = CreateIdentity(size);
            element.values[position] = (byte) (position+1);
            element.values[position+1] = (byte) position;
            return element;
        }

Creando la rotación:

        public static Element CreateRotation(int size)
        {
            byte[] values = new byte[size];
            for (int k = 0; k < size; k++)
            {
                values[k] = (byte)(k == size - 1 ? 0 : k + 1);
            }
            return new Element(values);
        }

Un CompleteGroup es un grupo con todos sus elementos dados en el constructor:

    public class CompleteGroup : BaseGroup
    {
        private List<IElement> elements;
        public CompleteGroup(List<IElement> elements)
        {
            this.elements = elements.Distinct().ToList();
        }
//...
    }

Un GeneratedGroup es el resultado de combinar un conjunto de elementos generadores:

    public class GeneratedGroup : CompleteGroup
    {
        public GeneratedGroup(params IElement[] generators)
            : base(ElementUtilities.ElementsClosure(generators))
        {
        }
    }

ElementsUtilities.ElementsClosure es generada por todas las multiplicaciones (a(a*b, b*a, a*b*b, a*c*b… ) de los elementos iniciales presentados (a, b, c, …)

Notablemente, las permutaciones de S son generadas usando un swap y una rotación:

    public class SymmetricGroup : GeneratedGroup
    {
        public SymmetricGroup(int size)
            : base(Element.CreateSwap(size), Element.CreateRotation(size))
        {
        }
    }

Se puede probar que todo grupo finito es un subgrupo de un grupo generado por estos dos elementos: el llamado grupo simétrico de permutaciones de n elementos.

Como mencioné en el anterior post, hay otra implementación de grupos finitos en AjGroups: usando elementos abstractos, no permutaciones concretas. Seré el tema de un próximo post.

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Tue, Jan 4 2011 9:39 by lopez | with no comments