DrosteSharp: Yet Another Thing You Shouldn’t Do With .NET’s JIT

July 19, 2008 by drakoniis

There are some very interesting features in .NET with little in the way of clear documentation. One of these is the CodeProvider: a way to use .NET compilers from within .NET. While this may seem a bit odd, it allows for some very advanced reflection, and things like scripting to be implemented without using any weird hacks (though the concept of including an entire set of compilers in the redistributable runtime is a bit… questionable).

Here is a hack I came up with, which uses “assembly recursion”. It’s actually quite efficient, since assemblies are cached, even if generated by CodeProvider (which saves dll’s of the compiled assemblies in your temp folder with a hash for a name).

I have two projects, once I call DrosteSharp, the other I call RecurseLib. DrosteSharp is a console application, RecurseLib is a class library referenced by DrosteSharp. To get this to work, under the properties for Recurse.cs, I set “Copy To Output Directory” to “Copy If Newer”.

The effect of this program is that it compiles a copy of itself, then accesses an object in the copy of itself through a shared interface, then calls a virtual function through the interface which starts the cycle again in the newly generated assembly.

Recurse.cs (in the DrosteSharp project):


using System;
using System.IO;
using System.Collections.Generic;
using System.CodeDom.Compiler;
using Microsoft.CSharp;

namespace DrosteSharp
{
  public class Recurse : RecurseLib.IRecurse
  {
    public override void Do()
    {
      Console.WriteLine("Do() called");

      string code;
      using (StreamReader reader = new StreamReader("Recurse.cs"))
      {
        code = reader.ReadToEnd();
      }

      CSharpCodeProvider compiler = new CSharpCodeProvider();
      CompilerParameters compilerParams = new CompilerParameters(
        new string[] { "System.dll", "RecurseLib.dll" });
      CompilerResults compilerResults = compiler.CompileAssemblyFromSource(
        compilerParams, new string[] { code });

      object inst = compilerResults.CompiledAssembly.CreateInstance("DrosteSharp.Recurse");
      ((RecurseLib.IRecurse)inst).Do();
    }
  }

  public class Program
  {
    static void Main(string[] args)
    {
      Recurse recurse = new Recurse();
      recurse.Do();
    }
  }
}

IRecurse.cs (in the RecurseLib project):


namespace RecurseLib
{
  public abstract class IRecurse
  {
    public abstract void Do();
  }
}

Box Filters

July 14, 2008 by drakoniis

I’ve been needing to get a tech blog for a while, so here it is finally. For my first entry I’m going to explain box filters (convolution matrices). It’s a pretty simple topic, but it has come up lately a few times, so I’m going to give a brief explanation and a possible implementation in C.

Box filters as mathematical objects take the form of square matrices.

Let \mathcal{B} _{k} (where k is and odd integer greater than 0) be a vector space of matrices over \mathbb{R}^{n} representing the set of all square convolution matrices (box filters) with kernel action size k and dimension n. Normally, box filters are 2-dimensional, since their (current) primary use is image processing. Blurs, edge-detection, etc can be implemented using these filters. To keep this short, I’m going to cover a simple box filter that operates on a 1-dimensional data set.

Let \mathcal{B} _{3} ( \mathbb{R}^{1} ) be a 1-dimensional box filter with kernel action size 3. A box filter of this type takes the form \begin{bmatrix} a && b && c \end{bmatrix} . Each element resulting from the box filter will be combination of the old element in the same position and its adjacent elements:

v'_{n} = a v_{n - 1} \, + \, b v_{n} \, + \, c v_{n + 1}

Say I’m given a 1-dimensional scalar array:

\begin{Bmatrix} 3 & 2 & 0 & 4 & 1 & 5 & 2 & 3 & 1 & 4  \end{Bmatrix}

Which, when graphed, looks like this:

If I wanted to smooth this uniformly, I could use the box filter: \frac{1}{3} \begin{bmatrix} 1 & 1 & 1  \end{bmatrix} In the cases where the kernel action area overlaps the edge, there are a few ways of applying the filter. One is to extend the edge value past the edge, another is to wrap the action area around to the other edge. Here are both results when the smoothing filter is applied:

Extended:

Wrapped:

For a less computational, more mathematical definition (for example, how these relate to general signal processing), google “convolution matrix”.

References:

http://docs.gimp.org/en/plug-in-convmatrix.html

#include <stdio.h> /* fprintf, printf */

enum Mode
{
  WRAP = 0,
  EXTEND = 1
};

/* filter assumed to be of kernel action area 3 */
void ApplyFilter(double *target, const double *source,
                 const double *filter, unsigned len, int mode)
{
  unsigned i;
  for(i = 1; i < (len - 1); i++)
  {
    target[i] = (filter[0] * source[i-1]) +
                (filter[1] * source[i])   +
                (filter[2] * source[i+1]);
  }

  switch(mode)
  {
    case WRAP:
      target[0]       = (filter[0] * source[len - 1]) +
                        (filter[1] * source[0])       +
                        (filter[2] * source[1]);
      target[len - 1] = (filter[0] * source[len - 2]) +
                        (filter[1] * source[len - 1]) +
                        (filter[2] * source[0]);
      break;

    case EXTEND:
      target[0]       = (filter[0] * source[0])       +
                        (filter[1] * source[0])       +
                        (filter[2] * source[1]);
      target[len - 1] = (filter[0] * source[len - 2]) +
                        (filter[1] * source[len - 1]) +
                        (filter[2] * source[len - 1]);
      break;

    default:
      fprintf(stderr, "Invalid mode specified!");
  }
}

void PrintSvgPath(const double *arr, unsigned len)
{
  unsigned i;

  printf("M %f, %f  ", 10.0, 100.0);

  for(i = 0; i < len; i++)
  {
    printf("L %f, %f  ", 10.0 + (i * 10.0), 10.0*(10.0 - arr[i]));
    printf("L %f, %f  ", 10.0 + ((i + 1) * 10.0), 10.0*(10.0 - arr[i]));
  }

  printf("L %f, %f", 10.0 + (len * 10.0), 100.0);
}

void PrintDoubleArr(const double *arr, unsigned len)
{
  unsigned i;

  printf("{ ");

  for(i = 0; i < len; i++)
  {
    printf("%.2f ", arr[i]);
  }

  printf("}\n");
}

int main()
{
  double source[]   = {3, 2, 0, 4, 1, 5, 2, 3, 1, 4};
  double filter[]   = {(1.0/3.0), (1.0/3.0), (1.0/3.0)};
  double wrap[10]   = {0};
  double extend[10] = {0};

  ApplyFilter(wrap,   source, filter, 10, WRAP);
  ApplyFilter(extend, source, filter, 10, EXTEND);

  PrintDoubleArr(source, 10);
  PrintDoubleArr(wrap, 10);
  PrintDoubleArr(extend, 10);

  puts("\n");
  PrintSvgPath(source, 10);
  puts("\n");
  PrintSvgPath(wrap, 10);
  puts("\n");
  PrintSvgPath(extend, 10);

  return 0;
}