Monday, May 24, 2010

A simple XML Grammar in Newspeak

Recently I've been doing some experiments for parsing XML in using Newspeak parser combinators.

Here's the grammar:


class XmlGrammar = ExecutableGrammar(
"Xml 1.0 grammar with namespaces"
|
openAB = char: $<.
closeAB = char: $>.
amp = char: $&.
semicolon = char: $; .
slash = char: $/.


topenAB = tokenFromChar: $<.
tcloseAB = tokenFromChar: $>.
tslash = tokenFromChar: $/.

comment = openAB , (char: $-),(char: $-),
((charExceptFor: $-) | ((char: $-), (charExceptFor: $-))) plus,
(char: $-),(char: $-),closeAB .

letter = (charBetween: $a and: $z) | (charBetween: $A and: $Z).
digit = charBetween: $0 and: $9.

colon = char: $:.

quote = (char:$') .
dquote = (char:$") .

eq = tokenFromChar: $= .

VersionNum = (char:$1), (char: $.) , (charBetween: $0 and: $9) plus.

VersionInfo = (tokenFromSymbol: #version), eq, ((quote, VersionNum,quote) | (dquote, VersionNum, dquote )).

EncName = letter, (letter | digit) star.

EncodingDecl = (tokenFromSymbol: #enconding) , eq , ((quote, EncName ,quote) | (dquote , EncName , dquote )).

yesNo = (tokenFromSymbol: #yes) | (tokenFromSymbol: #no).

SDDecl = (tokenFromSymbol: #standalone), eq, ((quote, yesNo ,quote) | (dquote , yesNo , dquote )).

XMLDecl = (char: $<) , (char: $?) ,(tokenFromSymbol: #xml), VersionInfo , EncodingDecl opt, SDDecl opt,
(tokenFromChar: $?), (char: $>).

dprolog = XMLDecl.

NameStartChar = letter | (char: $_) .

NameChar = NameStartChar | (char: $-) | (char: $.) | digit.

Name = NameStartChar, NameChar star.

QName = (Name, colon, Name)| Name.

TQName = tokenFor: QName.

EntityRef = amp, Name ,semicolon .

CharRef = amp, (char: $#), (((char:$x), (digit | letter) plus) | (digit plus)) ,semicolon .

Reference = EntityRef | CharRef.

AttributeContent1 = (charExceptForCharIn: {$< . $". $&. }) | Reference.


AttributeValue = (dquote, AttributeContent1 star,dquote) |
(quote, AttributeContent1 star,quote).

Attribute = TQName ,eq, AttributeValue.

EmptyElemTag = topenAB ,QName, Attribute star, tslash , closeAB .
STag = topenAB ,QName, Attribute star, tcloseAB .
ETag = topenAB ,slash,QName, closeAB .

CDStart = topenAB ,(char: $!),(char:$[),(tokenFromSymbol: #CDATA),(char:$[).
CDEnd = (char: $]),(char: $]),(char: $>).

CDSect = CDStart, (charExceptFor: $]) star , CDEnd.

CharData = tokenFor: ((charExceptForCharIn: {$&. $<}) plus).

content = CharData opt, ((element | Reference | CDSect), CharData opt) star.

ComplexElement = STag, content , ETag.

element = EmptyElemTag | ComplexElement .


|
)
...


Code for this experiment can be found here.

Thursday, March 11, 2010

Some basic image processing operations with F#

The previous post presented a way to access the image data from the Webcam using DirectShow.Net and F#. We can manipulate this data to do some basic image processing operations with it.

Converting image to gray scale



Many image processing operations and algorithms are defined for grayscale images. A simple way to convert the image to grayscale is the following:


let grayGrabber(transform) =
fun (width,height) ->
{ new ISampleGrabberCB with
member this.SampleCB(sampleTime:double , pSample:IMediaSample )= 0
member this.BufferCB(sampleTime:double , pBuffer:System.IntPtr , bufferLen:int) =
let grayImage = getGrayImage pBuffer bufferLen

let resultImage = transform width height grayImage

saveGrayImageToRGBBuffer resultImage pBuffer bufferLen
0
}



Given that we have:


let inline getGrayImage (data:IntPtr) (size:int) =
let grayImage = Array.create (size/3) (byte(0))
let pixelBuffer = Array.create 3 (byte(0))
let mutable it = 0
for i in 0..(size - 3 ) do
if (i + 1) % 3 = 0 then
Marshal.Copy(new System.IntPtr(data.ToInt32()+i),pixelBuffer,0,3) |> ignore
grayImage.[it] <- byte(float(pixelBuffer.[0])*0.3 +
float(pixelBuffer.[1])*0.59 +
float(pixelBuffer.[2])*0.11)
it <- it+1
grayImage

let inline saveGrayImageToRGBBuffer (grayImage:byte array) (data:IntPtr) (size:int) =
let mutable targetIndex = 0
for i in 0..(size/3 - 1) do
let p = grayImage.[i]
Marshal.WriteByte(data,targetIndex,p)
Marshal.WriteByte(data,targetIndex+1,p)
Marshal.WriteByte(data,targetIndex+2,p)
targetIndex <- targetIndex+3
()


The technique for converting the image to grayscale was taken from here.

Using this new grabber definition we can change the code from the previous post to do this:


let mediaControl,filterGraph = createVideoCaptureWithSampleGrabber
device
nullGrayGrabber
None


Given that nullGrayGrabber is defined as:

let nullGrayGrabber = grayGrabber (fun (_:int) (_:int) image -> image)


The original webcam output looks like this:



By applying this filter the webcam output looks like this:



Applying templates



With this definitions we can do a common operation in image processing called template convolution. Basically, this technique consists in applying an operation to each pixel of an image and its surrounding neighborhood . The operation is represented by a matrix, for example:


0.0 1.0 0.0
1.0 -1.0 1.0
0.0 1.0 0.0


To apply this template to the a pixel of the image at x',y' we write:


(0.0*image[x-1,y-1]) + (1.0*image[x,y-1]) + (0.0*image[x+1,y-1]) +
(1.0*image[x-1,y]) + (-1.0*image[x,y]) + (1.0*image[x+1,y]) +
(0.0*image[x-1,y+1]) + (1.0*image[x,y+1]) + (0.0*image[x+1,y+1])


The function to apply this kind of operation looks like this:

let convolveGray3 w h (image:byte array) (template:float[,]) hhalf whalf =

let result = Array.create (image.Length) (byte(0))

let getPixelGray' = getPixelGray w h image
let setPixelGray' = setPixelGray w h result

for y in (hhalf + 1) .. (h - ((Array2D.length1 template) - hhalf - 1) - 1 ) do
for x in (whalf + 1) .. (w - ((Array2D.length2 template) - whalf - 1) - 1 ) do

let mutable r = 0.0

for ty in 0 .. (Array2D.length1 template - 1) do
for tx in 0 .. (Array2D.length2 template - 1) do
let ir = getPixelGray' ( x + (tx - whalf)) ( y + (ty - hhalf))
r <- r + template.[ty ,tx ]*float(ir)

setPixelGray' x y (byte(Math.Abs r))

result


Given that:

let inline getPixelGray width height (image:byte array) x y  =
let baseHeightOffset = y*width
let offset = baseHeightOffset + x
image.[offset]

let inline setPixelGray width height (image:byte array) x y value1 =
let baseHeightOffset = y*width
let offset = baseHeightOffset + x
image.[offset] <- value1
()



We can represent operations such as edge detection or smoothing.
First order edge detection can be represented using the following template:


let firstOrderEdgeDetectTemplate =
(array2D [|[|2.0;-1.0|];
[|-1.0;0.0|];|])


Changing the code of the main program to the following:

let convGrayGrabber1 = 
grayGrabber (fun width height grayImage -> convolveGray3 width height grayImage firstOrderEdgeDetectTemplate 0 0 )


Now the output looks like:



We can also use a template template to represent averaging. This technique removes detail from the image by calculating the average value of pixel given its neighborhood. The definition of a function:

let averagingTemplate (windowSize) =
Array2D.create windowSize windowSize (1.0/float(windowSize*windowSize))


This function creates a template which looks like this:


> averagingTemplate 3;;
val it : float [,] = [[0.1111111111; 0.1111111111; 0.1111111111]
[0.1111111111; 0.1111111111; 0.1111111111]
[0.1111111111; 0.1111111111; 0.1111111111]]


We can change again the main program to use this function:

let averagingGrayGrabber = 
let template = averagingTemplate 3
grayGrabber (fun width height grayImage -> convolveGray3 width height grayImage template 1 1 )

...

let mediaControl,filterGraph = createVideoCaptureWithSampleGrabber
device
averagingGrayGrabber
None


The result image looks like this:



Final words


As with the previous post I'm using mainly the imperative features of F# . For future posts I'll try change this and also continue the exploration of image processing with F#.

Most of the techniques described here were taken from the "Feature Extraction & Image Processing" book by Mark S. Nixon and Alberto S. Aguado.

Code for this post can be found here.

Wednesday, February 24, 2010

Using a Webcam with DirectShowNET and F#

In this post I'm going to show a small F# example of using DirectShowNET to access a webcam and manipulate the image data.

DirectShow


DirectShow is a huge Windows API for video playback and capture. Among many things this API allows flexible access to data captured by video input devices such as a webcam.

DirectShowNET


The DirectShow is COM based API. According to the documentation, it's meant to be used from C++. Luckily there's DirectShowNET which is a very nice library that exposes the DirectShow interfaces to .NET languages .

Accessing the webcam


What I wanted to do for this example is to have access to the data of the image being captured at a given time. The DirectShow API provides the concept of a Sample Grabber which not only gives you access to the captured data, but also allows its modification .

The following example shows the use of a couple of functions defined below:


let device = findCaptureDevice

let mediaControl,filterGraph = createVideoCaptureWithSampleGrabber
device
nullGrabber
None



let form = new Form(Size = new Size(300,300), Visible = true,Text = "Webcam input")


let videoWindow = configureVideoWindow (form.Handle) 300 300 filterGraph

form.Closing.Add (fun _ ->
mediaControl.StopWhenReady()
Marshal.ReleaseComObject(videoWindow) |> ignore
Marshal.ReleaseComObject(mediaControl) |> ignore
Marshal.ReleaseComObject(filterGraph) |> ignore)


mediaControl.Run() |> ignore

Application.Run(form)


Running this program will show the following window:



Notice that we called the createVideoCaptureWithSampleGrabber function using the nullGrabber parameter. This parameter specifies a sample grabber that does nothing with the current frame. Here's the definition:


let nullGrabber =
fun (width,height) ->
{ new ISampleGrabberCB with
member this.SampleCB(sampleTime:double , pSample:IMediaSample )= 0
member this.BufferCB(sampleTime:double , pBuffer:System.IntPtr , bufferLen:int) = 0
}


We can change this sample grabber to something more interesting:


let incrementGrabber =
fun (width,height) ->
{ new ISampleGrabberCB with
member this.SampleCB(sampleTime:double , pSample:IMediaSample )= 0
member this.BufferCB(sampleTime:double , pBuffer:System.IntPtr , bufferLen:int) =
for i = 0 to (bufferLen - 1) do
let c = Marshal.ReadByte(pBuffer,i)
Marshal.WriteByte(pBuffer,i ,if c > byte(150) then byte(255) else c+byte(100))
0 }



We can change the program to use:


let mediaControl,filterGraph = createVideoCaptureWithSampleGrabber
device
incrementGrabber
None


Running the program we can see:



This new sample grabber increments each pixel value by 100 or leaves the maximum value to prevent overflow. As presented here the pixel information is provided as an unmanaged pointer.


Using DirectShowNet



DirectShow also has the concept of filters which are software components that are assembled together to mix various inputs and outputs. For this examples we're going to used only a couple of interfaces. The code for this post is based on the DxLogo sample provided with DirectShowNET.

First we define the module containing these functions:


module LangExplrExperiments.DirectShowCapture

open DirectShowLib
open System.Runtime.InteropServices
open System.Runtime.InteropServices.ComTypes


let private checkResult hresult = DsError.ThrowExceptionForHR( hresult )


The checkResult function is an utility function to check for the HRESULT of some of the calls to COM interfaces. Since DirectShowNET is a thin wrapper for these interfaces we need to use this function to check for errors.

The findCaptureDevice returns the first capture devices detected by DirectShowNET .


let findCaptureDevice =
let devices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice)
let source : obj ref = ref null
devices.[0].Mon.BindToObject(null,null,ref typeof<IBaseFilter>.GUID,source)
devices.[0]


The following functions define the capture filter and sample grabber. The createVideoCaptureWithSampleGrabber function is the entry point. We can specify a file name as the final parameter to save the captured data to a video file.


let private ConfigureSampleGrabber( sampGrabber:ISampleGrabber,callbackobject:ISampleGrabberCB) =
let media = new AMMediaType()

media.majorType <- MediaType.Video
media.subType <- MediaSubType.RGB24
media.formatType <- FormatType.VideoInfo

sampGrabber.SetMediaType( media ) |> checkResult
DsUtils.FreeAMMediaType(media);

sampGrabber.SetCallback( callbackobject, 1 ) |> checkResult


let getCaptureResolution(capGraph:ICaptureGraphBuilder2 , capFilter:IBaseFilter) =
let o : obj ref = ref null
let media : AMMediaType ref = ref null
let videoControl = capFilter :?> IAMVideoControl

capGraph.FindInterface(new DsGuid( PinCategory.Capture),
new DsGuid( MediaType.Video),
capFilter,
typeof<IAMStreamConfig>.GUID,
o ) |> checkResult

let videoStreamConfig = o.Value :?> IAMStreamConfig;

videoStreamConfig.GetFormat(media) |> checkResult

let v = new VideoInfoHeader()
Marshal.PtrToStructure( media.Value.formatPtr, v )
DsUtils.FreeAMMediaType(media.Value)

v.BmiHeader.Width,v.BmiHeader.Height

let createCaptureFilter (captureDevice:DsDevice)
(sampleGrabberCBCreator: int*int -> ISampleGrabberCB) =
let captureGraphBuilder = box(new CaptureGraphBuilder2()) :?> ICaptureGraphBuilder2
let sampGrabber = box(new SampleGrabber()) :?> ISampleGrabber;
let filterGraph = box(new FilterGraph()) :?> IFilterGraph2
let capFilter: IBaseFilter ref = ref null

captureGraphBuilder.SetFiltergraph(filterGraph) |> checkResult

filterGraph.AddSourceFilterForMoniker(
captureDevice.Mon,
null,
captureDevice.Name,
capFilter) |> checkResult


let resolution = getCaptureResolution(captureGraphBuilder,capFilter.Value)
ConfigureSampleGrabber(sampGrabber, sampleGrabberCBCreator(resolution) )

filterGraph.AddFilter(box(sampGrabber) :?> IBaseFilter , "FSGrabberFilter") |> checkResult


captureGraphBuilder,filterGraph,sampGrabber,capFilter.Value

let getMediaControl (captureGraphBuilder :ICaptureGraphBuilder2)
(sampGrabber: ISampleGrabber)
(capFilter:IBaseFilter)
(filterGraph:IFilterGraph2)
(fileNameOpt:string option)=
let muxFilter: IBaseFilter ref = ref null
let fileWriterFilter : IFileSinkFilter ref = ref null
try
match fileNameOpt with
| Some filename ->
captureGraphBuilder.SetOutputFileName(
MediaSubType.Avi,
filename,
muxFilter,
fileWriterFilter) |> checkResult

| None -> ()

captureGraphBuilder.RenderStream(
new DsGuid( PinCategory.Capture),
new DsGuid( MediaType.Video),
capFilter,
sampGrabber :?> IBaseFilter,
muxFilter.Value) |> checkResult

finally
if fileWriterFilter.Value <> null then
Marshal.ReleaseComObject(fileWriterFilter.Value) |> ignore
if muxFilter.Value <> null then
Marshal.ReleaseComObject(muxFilter.Value) |> ignore

filterGraph :?> IMediaControl


let createVideoCaptureWithSampleGrabber (device:DsDevice)
(sampleGrabberCBCreator: int*int -> ISampleGrabberCB)
(outputFileName: string option) =
let capGraphBuilder,filterGraph,sampGrabber,capFilter = createCaptureFilter device sampleGrabberCBCreator

let mediaControl = getMediaControl capGraphBuilder sampGrabber capFilter filterGraph outputFileName

Marshal.ReleaseComObject capGraphBuilder |> ignore
Marshal.ReleaseComObject capFilter |> ignore
Marshal.ReleaseComObject sampGrabber |> ignore

mediaControl,filterGraph



Also for the creation of the video window the following function is provided:

let configureVideoWindow windowHandle width height (filterGraph:IFilterGraph2) =
let videoWindow = filterGraph :?> IVideoWindow

videoWindow.put_Owner(windowHandle) |> checkResult
videoWindow.put_WindowStyle(WindowStyle.Child ||| WindowStyle.ClipChildren) |> checkResult
videoWindow.SetWindowPosition(0,0,width,height) |> checkResult
videoWindow.put_Visible(OABool.True)|> checkResult

videoWindow


For future posts I'm going to try some experiments with the pixel data provided by the sample grabber.

Monday, February 1, 2010

Using a Webcam with WIA and F#

In this post I'm going to show a small example of taking a picture using a Webcam with Windows Image Adquisition 1.0 . This API seems to have changed in Vista and above, the following code only applies to XP.

First step, create the interop assemblies:


C:\test\> TlbImp c:\WINDOWS\system32\wiascr.dll
Microsoft (R) .NET Framework Type Library to Assembly Converter 3.5.30729.1
Copyright (C) Microsoft Corporation. All rights reserved.

Type library imported to WIALib.dll

C:\test>TlbImp c:\WINDOWS\system32\wiavideo.dll
Microsoft (R) .NET Framework Type Library to Assembly Converter 3.5.30729.1
Copyright (C) Microsoft Corporation. All rights reserved.

Type library imported to WIAVIDEOLib.dll


Now we launch FSI and load the assemblies:


C:\test> fsi.exe

Microsoft F# Interactive, (c) Microsoft Corporation, All Rights Reserved
F# Version 1.9.7.8, compiling for .NET Framework Version v2.0.50727

For help type #help;;

> #r "WIALib.dll";;

--> Referenced 'C:\development\blog\wiafs\WIALib.dll'

> #r "WIAVIDEOLIB.dll";;

--> Referenced 'C:\development\blog\wiafs\WIAVIDEOLIB.dll'



Now we can list the capture devices:


> wia.Devices |> Seq.cast |> Seq.map (fun (x:WIALib.IWiaDeviceInfo) -> x.Name);;

val it : seq<string> = seq ["My iPod"; "Logitech QuickCam Chat"]



Now I'm going to use the QuickCam to take the picture so we get the information for this device (of type 'StreamingVideo'):


> let devInfo = wia.Devices |> Seq.cast |> Seq.filter (fun (x:WIALib.IWiaDeviceInfo) -> x.Type.Contains("StreamingVideo")) |> Seq.head;;

val devInfo : WIALib.IWiaDeviceInfo

> devInfo.Name;;
val it : string = "Logitech QuickCam Chat"


Now we create an instance of the 'WIAVIDEOLib.WiaVideoClass' which will let us use the Webcam.


> let vid = new WIAVIDEOLib.WiaVideoClass();;
Binding session to 'C:\development\blog\wiafs\WIAVIDEOLib.dll'...

val vid : WIAVIDEOLib.WiaVideoClass

> vid.ImagesDirectory <- "c:\\temp";;
val it : unit = ()
> let h = ref (new WIAVIDEOLib._RemotableHandle());;

val h : WIAVIDEOLib._RemotableHandle ref =
{contents = WIAVIDEOLib._RemotableHandle;}

> vid.CreateVideoByWiaDevID(devInfo.Id,h,0,1);;
val it : unit = ()



The 'ImagesDirectory' property specifies the location for the captured images.

Now we can take a picture:


> let outFileName = ref "";;

val outFileName : string ref = {contents = "";}

> vid.TakePicture( outFileName );;
val it : unit = ()
> outFileName;;
val it : string ref = {contents = "c:\temp\Imagen 009.jpg";}


The 'outFileName' parameter gets the name of the saved image in the images directory.

Monday, November 23, 2009

Adding automatic semicolon insertion to a Javascript parser

A couple of weeks ago I wrote a blog post about a Javascript parser written using the Newspeak parsing combinators. As mentioned in that post, no semicolon insertion was supported. This post shows how the feature was added.

Automatic semicolon insertion



As detailed in section 7.9 of the ECMA 262 document[PDF], in Javascript you can use newline as statement separator in some scenarios. For example a semicolon is "implicitly inserted" if expression-statements are separated by line terminators:


if (condition) {
print("A")
print("B")
}


This code snippet is equivalent to:



if (condition) {
print("A");
print("B");
}


Solution



In the a original post about the parser, espin pointed me out to a paper[PDF] by A. Warth that mentions how the semicolon insertion problem was solved in a Javascript parser written in OMeta. The solution presented is this post is based on the one from the paper.


I wanted to isolate the code that performs this function. So in order to add this functionality I created a subclass that overrides the productions that get involved in this process. This way we can have both a parser with and without the feature. Here's the code:


class JSGrammarWithSemicolonInsertion = JSGrammar (
"Parser features that add automatic semicolon insertion"
|

specialStatementTermination = ((( cr | lf ) not & whitespace ) star,
(semicolon | comment | lf | cr | (peek: $})) )
wrapper: [ :ws :terminator | | t | t:: Token new. t token: $;. t].

returnStatement = return, (specialStatementTermination |
(expression , specialStatementTermination)).

breakStatement = break, (specialStatementTermination |
(identifier , specialStatementTermination)).

continueStatement = continue, (specialStatementTermination |
(identifier , specialStatementTermination)).

whitespaceNoEOL = (( cr | lf ) not & whitespace ) star,
(((peek: (Character cr)) | (peek: (Character lf))) not) .

throwStatement = throw, whitespaceNoEOL , expression , specialStatementTermination.

expressionStatement = (((function | leftbrace) not) & expression), specialStatementTermination.

variableStatement = var, variableDeclarationList, specialStatementTermination.
|
)


The result of parsing the following code:


var x = 0
while (true) {
x++
document.write(x)
if ( x > 10)
break
else continue
}


... is presented using the utility created for the previous post:



Code for this post is available here.

Monday, October 19, 2009

A quick look at J

In this post I'm going to show a small overview of the J programming language. An example of polynomial multiplication is examined.

J


J is an array programming language derived from APL which means is good for manipulating arrays and matrices. Its syntax and semantics are very different from other languages which makes it an interesting topic for studying.

There's a lot of documentation and examples available from the J software website. Two complete tutorials are "Learning J" by Roger Stokes and "J for C programmers" by Henry Rich.

The J distribution also includes examples and tutorials. The examples will be presented using J's REPL called jconsole.

The example



In order to give an overview of the language I'm going to start from the definition of a function that performs polynomial multiplication and examine how it was constructed.

The function is defined as follows:

polymulti =: dyad : '+/ (((_1 * i. #y) (|. "0 1) ((x (*"_ 0) y) (,"1 1) (((#y) - 1) $ 0))) , 0)'


Writing this example helped me understand some of the J's basic concepts (I'm completely sure there's a better/more efficient way to do this!).

Polynomial multiplication



The basic technique for polynomial multiplication consists on multiplying each term of one of the polynomials by the order and them simply the result. For example:


(4x3 - 23x2 + x + 1) * (2x2 - x - 3)

= ((4x3 - 23x2 + x + 1) * 2x2) +
((4x3 - 23x2 + x + 1) * -x) +
((4x3 - 23x2 + x + 1) * -3)

= (8x5 - 46x4 + 2x3 + 2x2) +
(-4x4 + 23x3 - x2 - x) +
(-12x3 + 69x2 - 3x - 3)

= (8x5 - 50x4 + 13x3 + 70x2 - 4x - 3)


Now I'll start creating polymulti from the bottom up to the definition.

1. Defining polynomials



As mentioned above J is a nice language for manipulating arrays. We're going to use J arrays to define polynomials. In fact J supports some operations on arrays as polynomials which will be described bellow.

In order to write a new array literal containing 1,1, -23 and 4 in J we write (here using jconsole):


1 1 _23 4
1 1 _23 4


As you can see the elements of the array are separated by space. Also negative numbers are prefixed by underscore '_'. This array is going to be used to represent the coefficients of the "(4x3 - 23x2 + x + 1)" polynomial.

We're going to define two variables with the polynomials shown above to use them for examples:


p1 =: 1 1 _23 4
p2 =: _3 _1 2


Here the '=:' operator is used to bind the specified arrays with p1 and p2.

2. Multiply each element of one of the polynomials



We can proceed to apply the first step in the process which is multiply each element of the second operand by the first operand.

In J we can operate on arrays easily, for example if we want to multiply each element of the above array by a 2 we write:


1 1 _23 4 * 2
2 2 _46 8


In J the an operation that receives two arguments is called a dyad and a operation that receives only one is called monad. Here we're using the '*' dyad to perform the multiplication.

We cannot directly go and type "p1 * p2" because we will get the following error:


p1 * p2
|length error
| p1 *p2


This happens because the length of the two arrays (4 and 3) could not be used to perform the operation. We can apply '*' to a two same size arrays and J will multiply each element. For example:


p1 * p1
1 1 529 16


Now what I want is to multiply each element of 'p2' by 'p1'. In order to do this we can change the behavior of the '*' dyad by specifying its rank (more details on how to do this can be found in "Verb Execution -- How Rank Is Used (Dyads)") . To change the rank of '*' and say that we want to multiply the complete array on the left for each of the cells of the right array we write (*"_ 0) .For example:


p1 (*"_ 0) p2
_3 _3 69 _12
_1 _1 23 _4
2 2 _46 8


By specifying (*"_ 0) we say that the left operand has "infinite rank" (_) which means it will consider the array as single unit.We also say that for the right argument we will consider every cell (by using the 0 rank). Notice that in order to modify the rank we use double quote (") which, in J, doesn't have to paired with another double quote as in most programming languages.

Also you can notice that the result of this operation is an array of arrays, one for each element of the right argument.

2. Sum each element of one of the polynomials

Now that we have an array of polynomials with the result of multiplying the coefficients, we need to change the degree of each of the polynomials. First we need to make more space to increment the degree of the polynomials. We're going to use the ',' dyad which lets you concatenate two arrays. For example:


p1 , 0 0
1 1 _23 4 0 0


We need to append an array that is the size of the second polynomial minus one. In order to create a new array of this size we use '$' which lets you create an array or matrix by specifying the size and the value of the elements of the new array. For example:


10 $ 0
0 0 0 0 0 0 0 0 0 0


The size of the array can be obtained with the '#' monad. For example:


# p1
4


Now we can combine all these elements to resize each array resulting from the multiplication of the coefficients like this:


(p1 (*"_ 0) p2)
_3 _3 69 _12
_1 _1 23 _4
2 2 _46 8
(((#p2) - 1 ) $ 0)
0 0
(p1 (*"_ 0) p2) (,"1 1) ( ((#p2) - 1 ) $ 0)
_3 _3 69 _12 0 0
_1 _1 23 _4 0 0
2 2 _46 8 0 0


Here we use (((#p2) - 1 ) $ 0) to generate an array of zeros of the desired size. Then we use (,"1 1) which is the ',' dyad with a modified rank saying that each element of the left matrix (an array) will be concatenated with the second array (since the second argument is a single dimension array we could have said (,"1 _) ).

With the arrays resized we can change the degree of our polynomial array. In order to do this we're going to use the '|.' dyad which let's you rotate an array an specified amount of positions. For example:

 
1 |. 1 2 3
2 3 1
_1 |. 1 2 3
3 1 2


As shown in the example, by specifying a positive number the array will be rotated to the left and a negative number to the right.

Now the question is, how to rotate each element of the polynomial array by a different element count? Before showing that we're going to introduce the 'i.' primitive which lets you create an array of with a sequence of numbers for example, to create an array of 10 numbers (starting with 0) we write:


i. 10
0 1 2 3 4 5 6 7 8 9


We can use this primitive in conjunction with the rotate primitive to say


m =: (p1 (*"_ 0) p2) (,"1 1) ( ((#p2) - 1 ) $ 0)
i. #p2
0 1 2
_1 * i. #p2
0 _1 _2
(_1 * i. #p2) (|."0 1) m
_3 _3 69 _12 0 0
0 _1 _1 23 _4 0
0 0 2 2 _46 8


As you can see we use the array generated by (_1 * i. #p2) to specify how many positions are we moving. We apply the change the rank of '|.' by saying (|."0 1) which means apply '|.' for each single cell of the left array to each row of the right array.

The previous step generated an array polynomials to be summed. So the only thing left is to generate the final polynomial. In order to do this we use the '+/' dyad which let's use sum the contents of an array. For example:


+/ 5 3 4 1
13


We can apply +/ to any array and J will do the operation as expected.


+/ (_1 * i. #p2) (|."0 1) m
_3 _4 70 13 _50 8


As a work around I'm appending a zero row to this matrix, just in case the p2 array is a 0 degree polynomial.


+/ ((_1 * i. #p2) (|."0 1) m) , 0
_3 _4 70 13 _50 8


And that's it we have the complete process for multiplying the array.

3. Create the function

Now putting all the elements described above we can put together the polynomial multiplication dyad:

polymulti =: dyad : '+/ (((_1 * i. #y) (|. "0 1) ((x (*"_ 0) y) (,"1 1) (((#y) - 1) $ 0))) , 0)'


The 'x' and 'y' names are the implicit names of the left and right operands.

We can use it with any pair of polynomials. For example:


2 34 3 polymulti 4 3
8 142 114 9
2 34 3 polymulti 4 0 3
8 136 18 102 9
2 34 3 polymulti 1
2 34 3


4. Use the polynomials

J already has support for polynomials inside the library. For example by using the 'p.' we can get an evaluation of a given polynomial.


3 4 5 p. 34
5919
3 + (4*34) + (5*34*34)
5919
_2 p. 34
_2
(5 3 _2 polymulti 3 0 0 _2)
15 9 _6 _10 _6 4
(5 3 _2 polymulti 3 0 0 _2) p. 3
204


Final words



It was very interesting to read about J. It offers a different perspective on programming which is definitely worth studying. I have to admit it was difficult at the beginning because of the number of concepts to learn ( only a couple are presented in this post) and the syntax . For future posts I'm going to try to explore more J features.

Tuesday, October 6, 2009

AS3 Getter/Setter support in AbcExplorationLib

Recently I added initial support for reading and writing AS3/Avm2 getters and setters to AbcExplorationLib.

Given the following ActionScript class:


class Complex {
public var radius:Number;
public var angle:Number;
public function Complex(ar:Number,aa:Number):void {
radius = ar;
angle = aa;
}

public function set imaginary(newImaginary:Number):void
{
var oldReal = this.real;
angle = Math.atan(newImaginary/oldReal);
radius = Math.sqrt(oldReal*oldReal + newImaginary*newImaginary);
}
public function get imaginary():Number
{
return radius*Math.sin(angle);
}

public function set real(newReal:Number):void
{
var oldImaginary = this.real;
angle = Math.atan(oldImaginary/newReal);
radius = Math.sqrt(newReal*newReal + oldImaginary*oldImaginary);
}
public function get real():Number
{
return radius*Math.cos(angle);
}
}


We compile it using the Flex SDK:
java -jar c:\flexsdk\lib\asc.jar complexclasstest.as


Then we can load it using the library:


Microsoft F# Interactive, (c) Microsoft Corporation, All Rights Reserved
F# Version 1.9.6.16, compiling for .NET Framework Version v2.0.50727

Please send bug reports to fsbugs@microsoft.com
For help type #help;;

> #r "abcexplorationlib.dll";;

--> Referenced 'abcexplorationlib.dll'

> open System.IO;;
> open Langexplr.Abc;;
> let f = using (new FileStream("complexclasstest.abc",FileMode.Open)) (fun s -> AvmAbcFile.Create(s));;

val f : AvmAbcFile

> let complexClass = List.hd f.Classes;;

val complexClass : AvmClass


> complexClass.Properties |> List.map (fun p -> p.Name);;
val it : QualifiedName list =
[CQualifiedName (Ns ("",PackageNamespace),"real");
CQualifiedName (Ns ("",PackageNamespace),"imaginary")]
> let realGetter = complexClass.Properties |> List.map (fun p -> p.Getter.Value) |> List.hd;;

val realGetter : AvmMemberMethod:
> realGetter.Method.Body.Value.Instructions |> Array.map (fun x -> x.Name);;
val it : string array =
[|"getlocal_0"; "pushscope"; "getlocal_0"; "getproperty";
"findpropertystrict"; "getproperty"; "getlocal_0"; "getproperty";
"callprop"; "multiply"; "returnvalue"|]





The library can be found here.