Planet Squeak

blogs about Squeak, Pharo, Croquet and family
planet squeak - planet squeak es - planet squeak jp - planet croquet - planet squeak code - planet smalltalk

February 18, 2018

Torsten Bergmann

Three-valued logic

in Pharo. Project is here.

by Torsten (noreply@blogger.com) at February 18, 2018 08:28 PM

Hernan Morales

PI Announcement

Today I just released PI, a MIT-pip-like command line program for Pharo Smalltalk. PI stands for Pharo Install. It is written in bash and tested successfully under Windows (MSYS) and GNU/Linux. Currently supports listing and searching pacakges both in SmalltalkHub and GitHub, Pharo image installation, installing packages from SmalltalkHub, and more features comming. Everything is available

by Hernán (noreply@blogger.com) at February 18, 2018 08:09 PM

The Weekly Squeak

Call-for-Presentations 26th International Smalltalk Joint Conference

Call-for-Presentations 26th International Smalltalk Joint Conference
cagliari-2-crop
The ESUG board is pleased to announce that the 26th ESUG conference/summer-school will be held in Cagliari, Italy 10-14 September 2018; with Camp Smalltalk 8-9 September 2018. The conference is co-organized by University of Cagliari and the Agile Group of the faculty of computer science.
http://www.esug.org/wiki/pier/Conferences/2018/
This call includes:
– Developer Forum
– Smalltalk Technology Award
– International Workshop http://www.esug.org/wiki/pier/Conferences/2018/International-Workshop-IWST_18
– Student Volunteer http://www.esug.org/wiki/pier/Conferences/2018/Student-volunteers
You can support the ESUG conference in many different ways:
===============================================
– Sponsor the conference. New sponsoring packages are described at
              http://www.esug.org/wiki/pier/About/BecomeSponsor
– Submit a talk, a software or a paper to one of the events. See below.
– Attend the conference. We’d like to beat the previous record of attendance.
Students can get free registration and hosting if they enroll in the Student Volunteers program. See below.
Developers Forum: International Smalltalk Developers Conference
Call For Participation
================
We are looking for YOUR experience on using Smalltalk. You will have 30 min for presentations and 45-60 min for hand-ons tutorial.
The list of topics for the normal talks and tutorials includes, but is not limited to the following:
-Micro Services, Container, Cloud, Big Data,
-XP practices, Development tools, Experience reports
-Model driven development, Web development, Team management
-Meta-Modeling, Security, New libraries and frameworks
-Educational material, Embedded systems and robotics
-SOA and Web services, Interaction with other programming languages
-Teaching Pearls and Show us Your Business
-Show your business 10 min session (Get prepared!!)
How to submit?
============
Submissions deadline is 15 of June 2018
Notification of acceptance will be on done on the fly.
Pay attention: the places are limited so do not wait till the last minute to apply. Prospective presenters should submit a request to Stephane.Ducasse[at]inria.fr
AND USE THE following header [ESUG 2018 Developers] Title:
Please follow the template below the email will be automatically processed!
Name:
Email:
Abstract:
Bio:
Any presentation not respecting this form will be discarded automatically.
International Workshop on Smalltalk Technologies
======================================
Read the page: *http://www.esug.org/wiki/pier/Conferences/2018/International-Workshop-IWST_18*
Technology Award Competition
========================
The top 3 teams with the most innovative software will receive, respectively, 500 Euros, 300 Euros and 200 Euros during an awards ceremony at the conference. Developers of any Smalltalk-based software are welcome to compete. More information at http://www.esug.org/wiki/pier/Conferences/2018/Innovation-Technology-Awards
Student Volunteer Program
=====================
If you are a student wanting to attend ESUG, have you considered being a student volunteer? Student volunteers help keep the conference running smoothly; in return, they have free accommodations, while still having most of the time to enjoy the conference. More information at
http://www.esug.org/wiki/pier/Conferences/2018/Student-volunteers
We hope to see you there and have fun together.

by Ron Teitelbaum at February 18, 2018 06:12 PM

Torsten Bergmann

Squeak TiledMaps

It’s a package for Squeak Smalltalk. It can load and cache static, prerendered map tiles from a variety of sources including OpenStreetMaps, Bing Maps, and so on. Nice!

by Torsten (noreply@blogger.com) at February 18, 2018 10:15 AM

String Comparison Performance

Massive String Comparison Performance Boost Up-coming in the Cog VM. Read more.

by Torsten (noreply@blogger.com) at February 18, 2018 10:14 AM

Moldable analysis with Moose

by Torsten (noreply@blogger.com) at February 18, 2018 10:12 AM

The Weekly Squeak

Squeak TiledMaps

Tony Garnock-Jones:

It’s a package for Squeak Smalltalk. It can load and cache static, prerendered map tiles from a variety of sources including OpenStreetMaps, Bing Maps, and so on.

It includes a geocoder query service which maps free-text queries to regions of the planet’s surface. The service can be backed by the Nominatim service (associated with OpenStreetMaps), the Bing geocoder, the Google geocoder, and so on.

Selection of tilesets is independent of selection of geocoder, so you can mix and match.

The package includes a “slippy map” morph called TiledMapMorph, that allows interaction with a map using the mouse. It includes a few hooks for EToys, too, so EToys scripting of the map is possible.

See: http://wiki.squeak.org/squeak/2800 for more info.

by Ron Teitelbaum at February 18, 2018 12:44 AM

February 17, 2018

Clement Bera

Massive String Comparison Performance Boost Up-coming in the Cog VM

Hi all,

These days my student Sophie Kaleba is working on the optimizations of String operations in the Cog VM and I’m spending a few hours here and there helping her. The main idea is to add a numbered primitive for String comparison that would lead, I believed based on my experience with Sista, to around 10x performance boost in String comparison. However we’ll show in this post that the performance boost is way better than just 10x. Some applications, like parsers which use extensively String>>#= to test tokens, will benefit greatly from this optimization.

Primitive specification

The existing Misc plugin primitive was specified as follow:

ByteString class >> compare: string1 with: string2 collated: order
"Return 1, 2 or 3, if string1 is string2, with the collating order of characters given by the order array."

There were multiple things we wanted to change:

The final primitive we implemented is specified as follow (two versions since last parameter is optional):

ByteString >> compareWith: anotherString
ByteString >> compareWith: anotherString collated: order
"Return a negative Smi, 0 or a positive Smi if self is anotherString, with the collating order of characters given optionnally by the order array."

We’ve moved away from class-side to instance-side. Based on our Java friends advises we decided not to answer -1, 0 or 1 but a negative Smi, 0 or positive Smi since it improves a lot performance (we’ll talk about that in next section). The last parameter is optional.

Primitive implementation

Basically we wrote all cases in pure Slang using direct SpurObjectMemory APIs since it’s a numbered primitive, then we re-wrote the common case (no order) in the JIT’s RTL opcodes.

I’m not going to show all the Slang code here since it’s horrible to read without syntax coloring, but we’ve written it in quite a fancy way. Here are the 2 calls (depending if the optional order parameter is present) the the main comparison loop and the loop itself :


order
  ifNil:
    [self
      rawCompare: string1
      length: strLength1
      with: string2
      length: strLength2
      accessBlock: [:str :index | objectMemory fetchByte: index ofObject: str ]]
   ifNotNil:
    [self
      rawCompare: string1
      length: strLength1
      with: string2
      length: strLength2
      accessBlock: [:str :index | objectMemory fetchByte: (objectMemory fetchByte: index ofObject: str) +1 ofObject: order ]]

rawCompare: string1 length: strLength1 with: string2 length: strLength2 accessBlock: accessBlock
  | c1 c2 min |
  <inline: true>"needs to be forced else slang does not inline it by default"
  min := strLength1 min: strLength2.
  0 to: min-1 do:
    [:i | c1 := accessBlock value: string1 value: i.
    c2 := accessBlock value: string2 value: i.
    c1 = c2 ifFalse: [^c1 - c2]].
  ^strLength1 - strLength2

We note two interesting things:

 
In Cog’s JIT, we rewrote only the version without the order parameter (Still trying mainly to optimize String>>=). We wrote multiple versions to evaluate performance. We’ve not trying pointer-size vectorization yet, but so far one of the simplest version seems to be the fastest, here is the 7-instructions comparison loop:

instr := cogit MoveXbr: TempReg R: string1Reg R: string1CharOrByteSizeReg.
cogit MoveXbr: TempReg R: string2Reg R: string2CharOrByteSizeReg.
cogit CmpR: string1CharOrByteSizeReg R: string2CharOrByteSizeReg.
jumpMidFailure := cogit JumpNonZero: 0.
cogit AddCq: 1 R: TempReg.
cogit CmpR: TempReg R: minSizeReg.
cogit JumpAboveOrEqual: instr.

Preliminary performance evaluation & C compiler non-sense

Once everything was ready, we evaluated the performance of the original Misc primitive, the new primitive with Slang version only and the new primitive with Slang & JIT version. We made the evaluation in the case where there is no order since we’re focusing on String>#=, so it’s a bit unfair for the old Misc primitive which has the indirection, but that’s the code that’s going to be run.

The micro-bench I am going to show is the following (it’s not that well written, hence the “preliminary” result):

{[ByteString compare: var with: var collated: (0 to: 255) asByteArray] benchFor: 5 second.
[ var compareSlangPrim: var] benchFor: 5 second.
[ var compareSlangAndJITPrim: var] benchFor: 5 second.

We ran it twice, once with a byteString of size 3 and once with a byteString of size 1008.

For the byteString of size 3, we got something like that:
#('116,000 per second. 8.6 microseconds per run.'
'44,800,000 per second. 22.3 nanoseconds per run.'
'71,600,000 per second. 14 nanoseconds per run.')

which leads to the Slang prim being 400x faster than the Misc primitive, and the jitted code 600x faster than the Misc primitive (Looks better than the expected 10x, doesn’t it ?). Small string evaluation is about testing the performance of all the non-loop comparison code: the subtraction at the end in our case instead of the multiple branches makes a difference here, quicker checks at the beginning of the primitive too. The removal of the order indirection makes a minor difference since the loop is used only 3 times. The jitted version is way faster than the Slang version since there’s no jit-to-C stack switch dance.

For the byteString of size 1008, interestingly, I got:
#('118,000 per second. 8.46 microseconds per run.'
'1,490,000 per second. 673 nanoseconds per run.'
'2,410,000 per second. 416 nanoseconds per run.')

while Sophie got:
#('101,000 per second. 9.93 microseconds per run.'
'1,950,000 per second. 513 nanoseconds per run.'
'1,970,000 per second. 508 nanoseconds per run.')

See the difference ? In my case, the jitted code is faster than Slang code on large String, while for Sophie it isn’t. Obviously we discovered that at 1 am yesterday and none of us could consider going to sleep before figuring out this non-sense. Fortunately, our first educated guess was the correct one, it’s a C compiler difference. On Mac OS X I have a LLVM compiled VM while on Linux Sophie has a GCC-compiled VM. We disassembled all the code to make sure our guess was correct.

Here are the three different versions of the tight comparison loop (no order):

LLVM
0001f644 movl -0x14(%ebp), %esi
0001f647 movzbl 0x8(%edx,%esi), %esi
0001f64c movl -0x18(%ebp), %edi
0001f64f movzbl 0x8(%edx,%edi), %edi
0001f654 subl %edi, %esi
0001f656 jne 0x1f660
0001f658 incl %edx
0001f659 cmpl %ebx, %edx
0001f65b jl 0x1f644

GCC
0x080623b0 : movzbl 0x8(%eax,%edx,1),%ebp
0x080623b5 : movzbl 0x8(%eax,%ebx,1),%ecx
0x080623ba : cmp %ecx,%ebp
0x080623bc : jne 0x80624b0
0x080623c2 : add $0x1,%eax
0x080623c5 : cmp %eax,%edi
0x080623c7 : jne 0x80623b0

Cog’s JIT
000018b2: movzbl %ds:(%edx,%eax,1), %edi
000018b6: movzbl %ds:(%esi,%eax,1), %ecx
000018ba: cmpl %edi, %ecx
000018bc: jnz .+0x0000003d
000018be: addl $0x00000001, %eax
000018c1: cmpl %eax, %ebx
000018c3: jnb .+0xffffffed

In the case of Sophie, the performance is the same because GCC and Cog's JIT generate almost exactly the same loop of 7 instructions. The main difference is that we use "jnb" instead of "jne", it's a micro-optimisation that we could integrate in the JIT in a further version (but that's I believe the kind of <1% performance optimisation). There's also this difference that GCC uses %ebp as a general purpose register (I checked GCC pushes %ebp on stack and pops it before returning), which is something we could consider doing too since we're lacking 1 register to optimize more this primitive (but we've tried multiple things and that version seems to be the best).

In my case, the LLVM code is simply horrible. LLVM does not succeed in keeping everything in registers leading to 2 spills that need to be reload at each iteration of the loop. The spills lead to two L1 memory reads and are the reason why the Slang primitive is slower than the jitted code on Mac. However, LLVM does this smart thing of using (subl, jne) while the other versions use (cmp, jne) and jump to the sub instruction if the branch is taken. Again we could integrate that in the JIT in a further version to earn <1% performance. LLVM also use the incl instruction instead of add $0x1, which is kind of fun but it does not make sense to do that in the JIT (we limit the number of instructions the RTL support to limit back-end complexity, incl is not part of the RTL instructions, and given that gcc does not use it, it most likely does not bring significant performance).

Retrospective & Considerations

Looking back at the byteString of size 3, I noticed that my results were also a little bit different that Sophie's (For pure Slang primitive, I got 35M/sec instead of 45M/sec due to this LLVM slower loop). I did not notice it at first but it's there and it's significant. Anyway there's an implementation in the JIT now which solves that problem.

Looking ahead at the loop version using order, we can see that the GCC version is also far better:

GCC
0x08062450 : movzbl 0x8(%ecx,%edx,1),%edi
0x08062455 : movzbl 0x1(%eax,%edi,1),%ebp
0x0806245a : movzbl 0x8(%ecx,%ebx,1),%edi
0x0806245f : movzbl 0x1(%eax,%edi,1),%edi
0x08062464 : cmp %edi,%ebp
0x08062466 : jne 0x80624a0
0x08062468 : add $0x1,%ecx
0x0806246b : cmp %ecx,%esi
0x0806246d : jne 0x8062450

LLVM
0001f5d4 movl %ebx, %edx
0001f5d6 movl -0x14(%ebp), %esi
0001f5d9 movzbl 0x8(%edi,%esi), %esi
0001f5de movl -0x10(%ebp), %eax
0001f5e1 movzbl 0x9(%esi,%eax), %esi
0001f5e6 movl -0x18(%ebp), %ebx
0001f5e9 movzbl 0x8(%edi,%ebx), %ebx
0001f5ee movzbl 0x9(%ebx,%eax), %ebx
0001f5f3 subl %ebx, %esi
0001f5f5 jne 0x1f665
0001f5f7 incl %edi
0001f5f8 movl %edx, %ebx
0001f5fa cmpl %ebx, %edi
0001f5fc jl 0x1f5d4

which makes me wonder... Should we write a jitted version for this case to avoid the LLVM slow-down on Mac? Should we report this somehow to the LLVM people so they may be able to fix it? The problem if we write this case in the JIT is that normally we don't do this hack that GCC does of using %ebp as a general purpose register, so we will lack a register on x86 to make it efficient. I mean we could do it, but it has to be done in some kind of platform-independent way which may not be obvious... Maybe we just have 1 read instead of the LLVM 3 reads on x86, and for ARMv5 and x64 we use one of the extra general purpose register? Or maybe we just ignore this case since it's not that common and pray the LLVM god to make this better?

Conclusion

We've just demonstrated through preliminary benchmarks that we've sped-up the String comparison operation by a factor ranging from 20x to 600x.

In the case of parsers, most string comparisons happen on small strings to test tokens, so parsers will benefit more from a 600x speed-boost than a 20x on String equality. I've got a JSON parser benchmark which is written in the dumbest way possible (it mainly uses strings over streams). In the Sista VM where string equality is rewritten at runtime as raw pointer-size vectorized byte comparison, the JSON parser bench is 10x faster (mostly because of the String equality optimization), I can't wait to see what are the results with this primitive. Although most likely you'll have to wait for the IWST paper to know about that ;-).

by Clement Bera at February 17, 2018 10:46 AM

February 16, 2018

Torsten Bergmann

Pharo TechTalk: Contributing

by Torsten (noreply@blogger.com) at February 16, 2018 07:52 AM

RSS Tools for Pharo

Tools to work with RSS feeds: https://brackendev.github.io/RSSTools-Pharo

by Torsten (noreply@blogger.com) at February 16, 2018 07:25 AM

February 14, 2018

Torsten Bergmann

The Moldable Editor

Read more here.

by Torsten (noreply@blogger.com) at February 14, 2018 12:43 AM

February 13, 2018

PharoWeekly

Iceberg 0.6.8 backported to 6.1

Hi,

I backported iceberg 0.6.8 to Pharo 6.1, so now it is in sync with the version on Pharo 7.0

Esteban

by Stéphane Ducasse at February 13, 2018 07:41 PM

February 12, 2018

Torsten Bergmann

Pharo VM synch with OSVM

Latest Pharo VM versions are based now on latest builds from OSVM. Read more.

by Torsten (noreply@blogger.com) at February 12, 2018 03:30 PM

Simple SMPP for Pharo

Simple SMPPv3.4 codec and connection library for Smalltalk/Pharo

by Torsten (noreply@blogger.com) at February 12, 2018 03:29 PM

Pharo Docu for MLNeuralNetwork

is here.

by Torsten (noreply@blogger.com) at February 12, 2018 03:24 PM

February 09, 2018

Ben Coman

A SignalR client for Pharo

I’m trying to hook into the real-time order book feed from the Bittrex cryptocurrency exchange, which comes via the signalr protocol on top of a websocket connection. Signalr is a Microsoft ASP.NET library designed to establish “persistent connections”. SignalR differentiates … Continue reading

by Ben Coman at February 09, 2018 03:14 PM

February 08, 2018

PharoWeekly

Cloudflare and Pharo

I needed to pass through a Cloudflare guard so made a tiny library that others may find useful.

https://github.com/Traadh/cloudflareun
Also I wrote a post detailing the background behind it…
http://blog.openinworld.com/2018/02/pharo-v-cloudflare/
cheers -ben

by Stéphane Ducasse at February 08, 2018 06:56 PM

Ben Coman

Pharo v. Cloudflare

In my pursuit to connect Pharo to the realtime order book feed of the Bittrex cryptocurrency exchange there are two main challenges: It uses Microsoft’s signalr protocol. The site is guarded by Cloudflare, which requires a Javascript puzzle to be … Continue reading

by Ben Coman at February 08, 2018 05:48 PM

February 07, 2018

PharoWeekly

sentry.io (OSS error tracking platform) SDK for Pharo

Hi,

I’ve made an experimental SDK for sentry.io to track errors in end-user installations.
Also usable as a Logger for Beacon (which I guess should be the primary way to use this).
… and  as an extension for Debugger (basically a replacement for ShoreLine, which is too simplistic for my needs).
https://github.com/peteruhnak/pharo-sentry
unnamed.png
Peter

by Stéphane Ducasse at February 07, 2018 07:18 PM

Signed VMs and Restored build process

Which means latest vm versions are latest builds from OSVM:

64bit

• http://files.pharo.org/get-files/70/pharo64-mac-latest.zip
• http://files.pharo.org/get-files/70/pharo64-linux-threaded-latest.zip
• http://files.pharo.org/get-files/70/pharo64-linux-latest.zip
• http://files.pharo.org/get-files/70/pharo64-win-latest.zip
32bit

• http://files.pharo.org/get-files/70/pharo-linux-threaded-latest.zip
• http://files.pharo.org/get-files/70/pharo-linux-latest.zip
• http://files.pharo.org/get-files/70/pharo-mac-latest.zip
• http://files.pharo.org/get-files/70/pharo-win-latest.zip

Hints

• MacOS VMs now are signed! This should fix a lot of problems we had before.
• Please take note that win64 build lacks all library dependencies, and many things will not work (working on that).
Thanks to Fabio to help me put all the pieces together.

cheers,
Esteban

by Stéphane Ducasse at February 07, 2018 05:26 PM

February 06, 2018

Torsten Bergmann

Pharo MineSweeper

MineSweeper implemented using Bloc in Pharo:


by Torsten (noreply@blogger.com) at February 06, 2018 02:15 PM

Pharo Pathfinder

Here is a video of Pathfinder - implemented using Bloc in Pharo.

by Torsten (noreply@blogger.com) at February 06, 2018 02:11 PM

PharoWeekly

I2C support to PharoThings and WiringPi

I added I2C support to PharoThings and WiringPi.
Now you can ask the board instance for I2C connection:
i2cConnection := board connectToI2CDevice: 4.
And then read/write data using wiringpi functions like:

i2cConnection readData.
i2cConnection read8BitsAt: 16r32 “register”.

i2cConnection writeData: 16rAB.
i2cConnection write8BitsAt: 16r32 “register” data: 16rA5.

I added also I2CDevice as superclass for simple i2c devices. There is example of accelerometer ADXL345. Look for details.
Best regards,
Denis

by Stéphane Ducasse at February 06, 2018 10:38 AM

Ben Coman

Pharo PDF Rendering, part 2, UFFI interfacing PDFium

Following on from Part 1 where we built PDFium from source into a shared library, we will replicate in Pharo the C example presented at the end of Part 1.  Lets review the  declaration prototypes of the function used, which we’ll … Continue reading

by Ben Coman at February 06, 2018 04:14 AM

February 05, 2018

Torsten Bergmann

Neural Network - Handwritten Digit Recognition

Pierce has written a very nice blog post on recognizing handwritten digits using neural networks in Pharo

by Torsten (noreply@blogger.com) at February 05, 2018 09:57 AM

February 04, 2018

Pierce Ng

Hello, digits!

The Hello World intro to machine learning is usually by way of the Iris flower image classification or the MNIST handwritten digit recognition. In this post, I describe training a neural network in Pharo to perform handwritten digit recognition. Instead of the MNIST dataset, I'll use the smaller UCI dataset. According to the description, this dataset consists of two files:

The files are in CSV format. Let's use the excellent NeoCSV package to read the data:

| rb training testing |

rb := [ :fn |
  | r |
  r := NeoCSVReader on: fn asFileReference readStream.
  1 to: 64 do: [ :i |
    r addFieldConverter: [ :string | string asInteger / 16.0 ]].
  "The converter normalizes the 64 input integers into floats between 0 and 1."
  r addIntegerField.
  r upToEnd ].

training := rb value: '/tmp/optdigits.tra'.
testing := rb value: '/tmp/optdigits.tes'.

Next, install MLNeuralNetwork by Oleksandr Zaytsev:

Metacello new 
  repository: 'http://smalltalkhub.com/mc/Oleks/NeuralNetwork/main';
  configuration: 'MLNeuralNetwork';
  version: #development;
  load.

MLNeuralNetwork operates on MLDataset instances, so modify the CSV reader accordingly:

| ohv rb dsprep training testing |

"Create and cache the 10 one-hot vectors."
ohv := IdentityDictionary new.
0 to: 9 do: [ :i |
  ohv at: i put: (MLMnistReader onehot: i) ].

"No change."
rb := [ :fn |
  | r |
  r := NeoCSVReader on: fn asFileReference readStream.
  1 to: 64 do: [ :i |
    r addFieldConverter: [ :string | string asInteger / 16.0 ]].
  "The converter normalizes the 64 input integers into floats between 0 and 1."
  r addIntegerField.
  r upToEnd ].

"Turn the output of 'rb' into a MLDataset."
dsprep := [ :aa |
  MLDataset new 
    input: (aa collect: [ :ea | ea allButLast asPMVector ]) 
    output: (aa collect: [ :ea | ohv at: ea last ]) ].

training := dsprep value: (rb value: '/tmp/optdigits.tra').
testing := dsprep value: (rb value: '/tmp/optdigits.tes').

Note MLMnistReader>>onehot: which creates a 'one-hot' vector for each digit. One-hot vectors make machine learning more effective. They are easy to understand "pictorially":

Since there are over 5,000 records, we precompute the one-hot vectors and reuse them, instead of creating one vector per record.

Now create a 3-layer neural network of 64 input, 96 hidden, and 10 output neurons, set it to learn from the training data for 500 epochs, and test it:

| net result | 
net := MLNeuralNetwork new initialize: #(64 96 10).
net costFunction: (MLSoftmaxCrossEntropy  new).
net outputLayer activationFunction: (MLSoftmax new).
net learningRate: 0.5.
net learn: training epochs: 500.

result := Array new: testing size.
testing input doWithIndex: [ :ea :i |
  | ret |
  ret := net value: ea.
  result at: i
    put: (Array 
            "'i' identifies the record in the test set."
            with: i
            "The neuron that is 'most activated' serves as the prediction."
            with: (ret indexOf: (ret max: [ :x | x ])) - 1 
            "The actual digit from the test set, decoded from its one-hot vector."
            with: ((testing output at: i) findFirst: [ :x | x = 1 ]) - 1) ].
result inspect.

From the inspector, we can see that the network got records 3, 6 and 20 wrong:

In the inspector's code pane, the following snippet shows that the network's accuracy is about 92%.

1 - (self select: [ :x | (x second = x third) not ]) size / 1797.0)

Not bad for a first attempt. However, the data set's source states that the K-Nearest Neighbours algorithm achieved up to 98% accuracy on the testing set, so there's plenty of room for improvement for the network.

Here's a screenshot showing some of the 8x8 digits with their predicted and actual values. I don't know about you, but the top right "digit" looks more like a smudge to me than any number.

Code to generate the digit images follows:

| mb | 
mb := [ :array :row :predicted :actual |
  | b lb |
  b := RTMondrian new.
  b shape box
    size: 1;
    color: Color gray.
  b nodes: array.
  b normalizer normalizeColorAsGray: [ :x | x * 16 ].
  b layout gridWithPerRow: 8;
    gapSize: 0.
  b build.
  lb := RTLegendBuilder new.
  lb view: b view.
  lb textSize: 9;
    addText: 'Row ', row asString, 
      ': Predicted = ', predicted asString,
      '. Actual = ', actual asString,
      '.'.
  lb build.
  b ].

rand := Random new.
6 timesRepeat: [
  | x |
  x := rand nextInt: 1797.
  (mb value: (testing input at: x)
    value: x
    value: (result at: x) second
    value: (result at: x) third)
  inspect ]

Let's also look at the failed predictions:

| failed |
failed := (result select: [ :x | (x second = x third) not ])
  collect: [ :x | x first ].
6 timesRepeat: [
  | x |
  x := rand nextInt: 1797.
  [ failed includes: x ] whileFalse: [ x := rand nextInt: 1797 ].
  (mb value: (testing input at: x)
    value: x
    value: (result at: x) second
    value: (result at: x) third)
  inspect ]

Putting the code altogether:

| ohv rb dsprep training testing net result mb rand failed |

ohv := IdentityDictionary new.
0 to: 9 do: [ :i |
  ohv at: i put: (MLMnistReader onehot: i) ].

rb := [ :fn |
  | r |
  r := NeoCSVReader on: fn asFileReference readStream.
  1 to: 64 do: [ :i |
    r addFieldConverter: [ :string | string asInteger / 16.0 ]].
  r addIntegerField.
  r upToEnd ].

dsprep := [ :aa |
  MLDataset new 
    input: (aa collect: [ :ea | ea allButLast asPMVector ]) 
    output: (aa collect: [ :ea | ohv at: ea last ]) ].

training := dsprep value: (rb value: '/tmp/optdigits.tra').
testing := dsprep value: (rb value: '/tmp/optdigits.tes').

net := MLNeuralNetwork new initialize: #(64 96 10).
net costFunction: (MLSoftmaxCrossEntropy  new).
net outputLayer activationFunction: (MLSoftmax new).
net learningRate: 0.5.
net learn: training epochs: 500.

result := Array new: testing size.
testing input doWithIndex: [ :ea :i |
  | ret |
  ret := net value: ea.
  result at: i 
    put: (Array 
            "'i' identifies the record in the test set."
            with: i
            "The neuron that is 'most activated' serves as the prediction."
            with: (ret indexOf: (ret max: [ :x | x ])) - 1 
            "The actual digit from the test set, decoded from its one-hot vector."
            with: ((testing output at: i) findFirst: [ :x | x = 1 ]) - 1) ].
result inspect.

mb := [ :array :row :predicted :actual |
  | b lb |
  b := RTMondrian new.
  b shape box
    size: 1;
    color: Color gray.
  b nodes: array.
  b normalizer normalizeColorAsGray: [ :x | x * 16 ].
  b layout gridWithPerRow: 8;
    gapSize: 0.
  b build.
  lb := RTLegendBuilder new.
  lb view: b view.
  lb textSize: 8;
    addText: 'Row ', row asString, 
      ': Predicted = ', predicted asString,
      '. Actual = ', actual asString,
      '.'.
  lb build.
  b ].

rand := Random new.
6 timesRepeat: [ 
  | x |
  x := rand nextInt: 1797.
  (mb value: (testing input at: x)
    value: x
    value: (result at: x) second
    value: (result at: x) third)
  inspect ].

failed := (result select: [ :x | (x second = x third) not ]) collect: [ :x | x first ].
6 timesRepeat: [
  | x |
  x := rand nextInt: 1797.
  [ failed includes: x ] whileFalse: [ x := rand nextInt: 1797 ].
  (mb value: (testing input at: x)
    value: x
    value: (result at: x) second
    value: (result at: x) third)
  inspect ]

by Pierce Ng at February 04, 2018 07:46 PM

February 02, 2018

Torsten Bergmann

MooseQuery

Moose-Query is a domain-specific language to build navigations and scopes queries for entities in Moose.

 More documentation is available here as well as the project itself.

by Torsten (noreply@blogger.com) at February 02, 2018 11:34 AM

February 01, 2018

Torsten Bergmann

Pharo as ticket machine

Pharo powered ticket machine for the Tournai Jazz festival. UI made with Spec framework. See it here.

by Torsten (noreply@blogger.com) at February 01, 2018 02:26 PM

January 31, 2018

PharoWeekly

HTTP mocking lib

Hi!

I started with a rudimentary HTTP mocking lib (adding features as needed) inspired by nock, but using the existing ZnClient / ZnRequest / ZnResponse api for mocking.

Available at https://lolg.it/herby/znock
Atm the feature are very basic (no filtering, matching only by host and scheme), but there it is for the interested.

Usage:

setUp
“other stuff”
Znock default intercept

tearDown
“other stuff”
Znock default verify

testFooBar
https://foo.bar‘ znock
url: ‘/api/v0/info’;
get;
ok: (ZnEntity json: self sampleInfoResponse).
“code that should get https://foo.bar/api/v0/info

The setUp starts and cleans the mocker; the test case sets up the expectation that GET https://foo.bar/api/v0/info will occur and defines the response; tearDown checks that that GET actually appeared and fails if not.

DNU w/ whitelisting is used to reply certain ZnClient messages to set up the expectation, ZnResponse class messages to create the response and ZnResponse messages to fill it further.

So you can

‘foo.bar’ znock
https;
url: ‘/api/v0/info’;
get;
notModified.

if you like it this way or

‘foo.bar’ znock
url: ‘/api/v0/info’;
get;
notModified.

to allow both http and https; eventually

‘foo.bar/api/v0/info’ znock
get;
notModified.

if you want it shorter; mocking multiple req/res pair should work (not tested), as in

‘foo.bar’ znock
url: ‘/api/v0/info’;
get;
notModified;
url: ‘/api/v0/last’;
get;
ok: (ZnEntity textCRLF: ‘herby’).

Both must appear (in any order) for verify to be happy.

Herby

 

 

by Stéphane Ducasse at January 31, 2018 07:54 PM

January 30, 2018

PharoWeekly

Sending notifications from Pharo to your Mobile via Pushover.net

Hi,
Just a little snippet I wanted to share. Pushover (https://pushover.net) is a general service that delivers notifications to iOS, Android and desktop devices via an API (and an email gateway as well). It is really easy to get started with.
This is how you do it from Pharo:
ZnClient new
systemPolicy;
url: ‘https://api.pushover.net/1/messages.json‘;
accept: ZnMimeType applicationJson;
contentReader: [ :entity | NeoJSONObject fromString: entity contents ];
contentWriter: [ :object | ZnEntity json: object asString ];
contents: (NeoJSONObject new
token: ‘ax4o55o6g5imb1a6st3m9x34hqu44z’;
user: ‘uv2fovx3f9sp3rgssrupvjgvdo8quw’;
title: ‘Test 3’;
message: (‘This is a test @ {1} by {2}.’ format: {
                            DateAndTime now. SystemVersion current }));
post.
It will look like this on your mobile device (just seconds later):
unnamed.png

by Stéphane Ducasse at January 30, 2018 08:24 AM