Wednesday, September 21, 2016

String to Enum parsing


The normal way of parsing an string containing an enum value:

var text = "Unknown";
var parsed = (KnownType)Enum.Parse(typeof(KnownType), text, true);

I've always found this to be ugly when scattered in the code base and usually I solve it by adding the following string extension to the projects utility class:

public static <T> ParseEnum(this string s)
{
    return (T) Enum.Parse(typeof (T), s, true);
}

Usage:

var text = "Unknown";
var parsed = text.ParseEnum<KnownType>();


Hope this helps someone out there

Thursday, September 15, 2016

Knowledge based reasoning in .net c#


I've lately been working on a side project in AI. One of the key parts of it is to figure out how to include a knowledge base and let the program reason about things itself. So how to model knowledge?


Other articles in the AI Knowledge Based Reasoning series on this site:
Knowledge based reasoning in .net c#
Reasoning in Open or Closed models
Logic Expression evaluation with open-world assumption
Expression evaluation on object based models
Expression evaluation over time
Expression evaluation over time - Was?

Prolog

Somewhere in the back of my head I have a class that I took back in university that scratched the surface of the Prolog language.
In a very simplified way the Prolog language uses facts and rules.

Facts in Prolog are in the form:

cat(pixel)

In other words, it is a known fact that pixel is a cat.
You can then go ahead and as for all the cats and get back pixel.
The fun things start when you define the rule that cat is an animal

animal(X) :- cat(X)

and start asking about animals and get back pixel.
A special case of rule you add a tuple and thus basically gain a relation

brotherOf(prime, pixel)
brotherOf(tiger, pixel)

meaning that prime and tiger and brothers to pixel.

As said, this is a very vague memory from the back of my head. If you are looking for a Prolog tutorial, then this is not the post for you.

Modelling knowledge

So, my approach to model knowledge is influenced by Prolog but that's about it. As I want the application to create the knowledge by itself there is no need to write a complicated textual representation, just a model that can be added to a queried. The textual representation used in this article are just there to make it easier to write about it
The model will be

attribute(variable)
relation(variable1, variable2)
variable1 => variable2

In this first version it is also assumed that all variables are strings. The attribute, relation and implication names are also treated as strings.

Some code for the knowledge model:

public class KnowledgeAttribute
{
 public string Attribute { get; set; }
 public string Subject { get; set; }
 public override string ToString()
 {
  return $"'{Attribute}'('{Subject}')";
 }
}
public class KnowledgeImplication
{
 public string Implicator { get; set; }
 public string Implied { get; set; }
 public override string ToString()
 {
  return $"'{Implicator}' => '{Implied}'";
 }
}
public class KnowledgeRelation
{
 public string Relation { get; set; }
 public string Subject { get; set; }
 public string Target { get; set; }
 public override string ToString()
 {
  return $"'{Relation}'('{Subject}', '{Target}')";
 }
}

So nothing too complicated there. Lets for simplicity store them in a holding object
public class KnowledgeModel
{
 public Dictionary<string, KnowledgeAttribute> Attributes { get; set; }
 public Dictionary<string, KnowledgeRelation> Relations { get; set; }
 public Dictionary<string, KnowledgeImplication> Implications { get; set; }

 public KnowledgeModel()
 {
  Attributes = new Dictionary<string, KnowledgeAttribute>();
  Relations = new Dictionary<string, KnowledgeRelation>();
  Implications = new Dictionary<string, KnowledgeImplication>();
 }
}

Querying

Now we can start querying the model. To get all variables with the same attribute:
public HashSet<string> ListAllWith(string attribute)
{
 return new HashSet<string>(from x in _model.Attributes.Values
  where
   x.Attribute.Equals(attribute, StringComparison.OrdinalIgnoreCase)
  select x.Subject
  );
}
Get variables matching a list of attributes
public HashSet<string> ListAllWith(IEnumerable attributes)
{
 HashSet<string> result = null;
 foreach (var attribute in attributes)
 {
  var found = ListAllWith(attribute);
  if (found.Count == 0)
   break; // nothing matches all attributes

  if (result == null)
   result = found;
  else
   result.IntersectWith(found);

  if (result.Count == 0)
   break; // nothing matches all attributes
 }
 return result;
}
Get all implications
private HashSet<string> GetAllImplications(string implied)
{
 var result = new HashSet<string>();
 result.UnionWith(from x in _model.Implications.Values
  where x.Implied.Equals(implied, StringComparison.OrdinalIgnoreCase)
  select x.Implicator);
 var chained = new HashSet<string>();
 foreach (var item in result)
 {
  chained.UnionWith(GetAllImplications(item));
 }
 result.UnionWith(chained);
 result.Add(implied);
 return result;
}
Or all related
public HashSet<string> ListAllRelated(string relationType, string variable)
{
 var relationTypes = GetAllImplications(relationType);
 return new HashSet<string>(from x in _model.Relations.Values
  where
  relationTypes.Contains(x.Relation)
  && x.Target.Equals(variable, StringComparison.OrdinalIgnoreCase)
  select x.Subject
  );
}

So. now just fill it with data and start querying.
Hope this helps someone out there

All code provided as-is. This is copied from my own code-base, May need some additional programming to work.

For example source code, head over to my github repository and play around for yourself:

Good luck :)

This is part of a series of posts regarding Knowledge modelling and expression evaluation.
The next part is
Logic Expression evaluation with open-world assumption

Saturday, April 13, 2013

C# array compress and decompress with GZipStream

A small utility class for compressing and decompressing using the GZip algorithm that is built into the .NET framework class GZipStream.
The GZipStream class works with streams, so we need to create a stream to be able to use it. I.e. the GZipStream will write to a stream and also read from a stream.

Compress

For the Compress function we will create a MemoryStream and wrapping it with a using statement so that it is correctly disposed when it leaves scope. We nest a creation of a GZipStream and pass it our MemoryStream and set the compression level to optimal.
Available compression levels are

  • Optimal. Can take a little longer, but will compress the data as best as it can
  • Fastest. Will do a fast compression, the data might not be compressed fully, but sometimes this is good enough.
  • NoCompression. Will not compress, just encode it as a gzip
Then it is just to write the byte array to the GZipStream and call the ToArray() function on the MemoryStream to receive the underlying byte array that can be used.


public static class Compression
{
    public static byte[] Compress(byte[] data)
    {
        using (var ms = new MemoryStream())
        {
            using (var gzip = new GZipStream(ms, CompressionLevel.Optimal))
            {
                gzip.Write(data, 0, data.Length);
            }
            data = ms.ToArray();
        }
        return data;
    }
    public static byte[] Decompress(byte[] data)
    {
        // the trick is to read the last 4 bytes to get the length
        // gzip appends this to the array when compressing
        var lengthBuffer = new byte[4];
        Array.Copy(data, data.Length - 4, lengthBuffer, 0, 4);
        int uncompressedSize = BitConverter.ToInt32(lengthBuffer, 0);
        var buffer = new byte[uncompressedSize];
        using (var ms = new MemoryStream(data))
        {
            using (var gzip = new GZipStream(ms, CompressionMode.Decompress))
            {
                gzip.Read(buffer, 0, uncompressedSize);
            }
        }
        return buffer;
    }
}

Decompress

For the decompress part we will start with figuring out the length of the uncompressed size by reading the first four bytes of the input array and converting those to a integer.
After that we create our resulting output byte array to the uncompressed size.
And then again with the MemoryStream and GZipStream, this time we send in the Decompress enum member to specify that we want to decompress the stream.
Note that we call the MemoryStream constructor with the input byte array and that we use the GZipStream to read to the resulting buffer from position 0 to the uncompressed size of the data.

Hope this helps someone out there!