Jan 29, 2012

Slightly More Complex Jasmin Bytecode

Here's my Jasmin code for calculating Fibonaci numbers. Note that I call a method passing a parameter and consuming a return value. Woot! What a shame that the jsr bytecode instruction can't be (mis)used as a cheaper form of recursive method call...

.class public Fibonaci
.super java/lang/Object

.method private static calc(I)I
.limit locals 3
.limit stack 100

; fib 0 = 0
iload_0
ifne Case2
iconst_0
ireturn

Case2:
; fib 1 = 1
iload_0
iconst_1
isub
ifne Case3
iconst_1
ireturn

Case3:
; fib n = fib (n-1) + fib (n-2)
iload_0
iconst_1
isub
invokestatic Fibonaci/calc(I)I
istore_1

iload_0
iconst_2
isub
invokestatic Fibonaci/calc(I)I
istore_2

iload_1
iload_2
iadd
ireturn

.end method

.method public static main([Ljava/lang/String;)V
.limit locals 3
.limit stack 3

bipush 10
istore_1

iload_1
invokestatic Fibonaci/calc(I)I
istore_2

iload_2
invokestatic java/lang/String/valueOf(I)Ljava/lang/String;
astore_2

getstatic java/lang/System/out Ljava/io/PrintStream;
astore_1

aload_1
aload_2
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V

return
.end method

Jasmin Training Wheels

What's the simplest not-completely-trivial JVM code you could write? I thought it would be calculating 10 factorial and printing it out. My first run at the code worked. Yay! Here's the Jasmin file:

.class public Factorial
.super java/lang/Object

.method public static main([Ljava/lang/String;)V
.limit locals 3
.limit stack 3

bipush 1
istore_1

bipush 10
istore_2

Repeat:

iload_1
iload_2
imul
istore_1

iinc 2 -1
iload_2
ifne Repeat

iload_1
invokestatic java/lang/String/valueOf(I)Ljava/lang/String;
astore_2

getstatic java/lang/System/out Ljava/io/PrintStream;
astore_1

aload_1
aload_2
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V

return
.end method
This was my JVM instruction set reference.

PDX AI Meeting -- Monday January, 30th at Jive

Are you an AI or ML hobbyist or practioner? Have a background in theory? Keen to learn from others and share what you've been working on? Come to the PDX AI meeting Monday, January 30th at Jive.

Jan 20, 2012

Gradle Goodness

This is my final installment, and it's a biggie! This post includes:
* automatically opening test reports on test failure
* grouping tasks for the gradle task list
* renaming all your build.gradle files to match the names of the subprojects
* plugin extensions as the replacement for plugin conventions
* changing the project's artifactId (useful for non-uploadArchive tasks consuming the pom)
* dependency specifications for easy reuse of customizations such as exclusions in multi-project builds

Automatically opening test reports on test failure. As an added bonus, your headless CI server will return false for Desktop.isDesktopSupported(). Note that this requires JDK 1.6:

test {
successful = true

afterTest { desc, result ->
if (result.toString() == 'FAILURE') {
successful = false
}
}
}

import java.awt.Desktop

gradle.taskGraph.afterTask { task, taskState ->
if (task instanceof Test && !task.successful) {
if (Desktop.isDesktopSupported()) {
Desktop.desktop.browse( new File(task.testReportDir, 'index.html').toURI() )
}
}
}
Grouping tasks for the gradle task list. Make use of the Task.group property:
task build(dependsOn: [test, assemble]) {
group = 'build'
}
Renaming all your build.gradle files to match the names of the subprojects. Place this in your settings.gradle:
rootProject.children.each { project ->
String fileBaseName = project.name.replaceAll("\\p{Upper}") { "-${it.toLowerCase()}" }
project.buildFileName = "${fileBaseName}.gradle"
}
Plugin extensions as the replacement for plugin conventions:
project.extensions.myextension = [name: "default"]

myextension.name = "some other value"

myextension {
name = "a different value"
}
Changing the project's artifactId (useful for non-uploadArchive tasks consuming the pom):
project.archivesBaseName = "my-preferred-artifactId"
Dependency specifications for easy reuse of customizations such as exclusions in multi-project builds. Use: dependencies.create(notation, closure).

Enjoy!

Jan 18, 2012

Gradle Goodness

A few more of today's learnings in Gradle:

When migrating build script code to a plugin you will typically need to add project. in places (because the delegate of a Gradle build script is the project). You can use Project.configure to make the migration smoother, e.g.:

apply plugin: MyPlugin

class MyPlugin implements Plugin {
void apply(Project project) {
project.configure(project) {
version '1.0' // instead of project.version '1.0'
}
}
}
For testing your Gradle plugins you can use ProjectBuilder.builder().build() to test the wiring of your plugin. For integration testing there's GradleDistributionExecutor, BUT it's not publically exposed - so please vote for the testing toolkit roadmap item to see this feature sooner.

So you know about the Copy task. Ever find yourself wanting to be certain that the destination folder is clean of other output? use the Sync task. Very nice.

Find yourself wanting to configure all current and future tasks matching a certain criteria? Take a look at the project.tasks. E.g.:
tasks.withType(Jar) {
aProperty = 'value'
}
Enjoy!

Jan 17, 2012

Gradle Goodness

A little known fact is that in Gradle you can now change property assignments into method calls in your build scripts (essentially by omitting the equals sign). Here's the good part: if the property does not exist the build script will fail. Yay! No more silent typo bugs! To illustrate, this works:

version = '1.0'
As does this:
version '1.0'
But this build script will fail:
versionxxx '1.0'
Nice!

Another tip:

Rather than make use of afterEvaluate you may be able to make good use of lazy GStrings. For example you could define your project version as "version-${-> buildNumber}"! See the explanation of Groovy lazy GString syntax for more information.

Did you know that the --exclude-task (-x) command-line switch differs from skipping tasks in that it prunes away the whole task graph associated with the excluded task? I didn't!

Finally, if your company is putting a lot of effort into customizing the Gradle experience, did you know that you could take advantage of Gradle init scripts in the Gradle init.d folder? Yes? Fiddly though, isn't it? Did you know that you can bundle your custom init scripts inside a Gradle distribution?!

To use this you need to assemble a Gradle distribution zip (basically by adding your init.d scripts to it), make it available internally (say, in your Artifactory repository), and then simply edit your gradle/wrapper/gradle-wrapper.properties. In there is the URL to download the Gradle distribution (distributionUrl).

Enjoy!

Jan 12, 2012

Hackergarten in PDX - Friday January 20th

I'm taking advantage of Luke Daley coming to town next week, and organizing the first US Hackergarten here in Portland. The idea is to come up with an improvement to an open source project in a short period of time. I plan to work on GRADLE-1677. So far participants include:
* Luke Daley (of Geb, and Gradle)
* Howard Lewis Ship (of Tapestry)

YesMail is hosting, and we kick off at 6pm on Friday January the 20th. Are you interested? RSVP and I'll send you all the details.

Jan 9, 2012

Machine Learning: Applying Anomaly Detection to Real World Problems

I've had a lot of success applying an Anomaly Detection algorithm to a problem at work. Without revealing anything sensitive, essentially the idea is be able to flag actions taken by the user of the system as "anomalies" and take preventative action.

There are many ways to do anomaly detection. My data has some characteristics that made the Multivariate Gaussian approach a good fit, namely:

* most features follow a normal distribution
* anomalies have features with values on extreme ends of the scale (i.e a number of standard deviations away from the mean)
* feature values are interrelated (i.e. a large value in feature A tends to correspond to a large value in feature B)

I didn't apply Principle Component Analysis. I wanted to see how good the results were before complicating the solution. As it turns out, it does pretty well. I had 4271 examples - of which only 3 were labelled as known anomalies. Only 0.5% (24) examples were predicted to be anomalies. All three known anomalies were found, and a further four were uncovered after hand labeling the remaining 21. Very nice indeed!

This results in a fantastic seeming F1 score (0.998). The fallacy in the calculation is that I haven't hand labeled a representative set of the unlabeled data - i.e. I've made the dangerous assumption that all examples predicted to be normal are indeed normal, and that there were no anomalies in fact predicted to be normal.

Very rewarding, none the less. All of this enabled by Octave of course. Ahh: hist(X(:,2))

Node: Reading Every Line in a File

In Groovy this would be concise: new File(filename).eachLine { ... }. Here's what it looks like in Node using CoffeeScript:

fs = require('fs')
EM = require('events').EventEmitter
ev = new EM()
stream = fs.createReadStream(filename)
buffer = new Buffer(0)
stream.on 'data', (data) ->
nextBuffer = new Buffer(buffer.length+data.length)
buffer.copy(nextBuffer)
data.copy(nextBuffer, buffer.length)
start = 0
offset = buffer.length
buffer = nextBuffer

for i in [1..data.length]
if data[i] == 10
end = i+offset+1
line = buffer.slice start, end
start = end
ev.emit "line", line.toString()

buffer = buffer.slice start

stream.on 'end', () ->
ev.emit 'line', buffer.toString() unless buffer.length == 0

ev.on 'line', (line) ->
...
Do you have a smarter way of doing this?

Edit: I'm reading a very large file with this code. That's why this isn't synchronous.

Jan 3, 2012

Escaped HTML in Jade Layout Body

Jade makes for very readable HTML. The one hurdle that got me was how to reference the body of your view without escaping the HTML. I had been using #{body}, whereas this does the right thing: div.postings!= body.

CoffeeScript Frustrations (in TextMate)

If you're using CoffeeScript in TextMate and you're getting some wierd behaviour (for me are variables being undefined), then TextMate's tabbing may be the problem. First, verify that this is your problem by inspecting the generated JavaScript. If it's the tabbing, switch TextMate to soft tabs.