Monday, May 29, 2006

Beautify Fixtures (Ruby on Rails)

After generating fixtures from my development database (you can read about it here) I decided to make them nice.

Up to now, for example, Permissions were labelled permission_001 and so on. And that is quite counter-intuitive. A good convention to label permissions would be controller_action. For example:

user_new: 
action: new 
id: 19 
controller: user 

The same applies to roles (you can label them with their name) and permissions_roles (you can build the name from their associated role and permission names). This is what my small script does. It is a rake task.
desc "Labels Roles, Permissions and PermissionsRoles after their value so that
the fixture becomes more readable. You can specify the DIR where fixtures we want to modify are.

require 'yaml' 
class Hash 
    def find_item(key, value, default=nil) 
        each do |k, v| 
            return k if (v[key] == value) || (v[key] == value.to_i) 
        end 
        default 
    end 
end 

task :beautify_fixtures => :environment do 
    dir = ENV['DIR'] || "#{RAILS_ROOT}/test/fixtures" 
    db   = ENV['DB']   || 'development' 
    File.cp "#{dir}/roles.yml",             "#{dir}/roles.bkp.yml" 
    File.cp "#{dir}/permissions.yml",       "#{dir}/permissions.bkp.yml" 
    File.cp "#{dir}/permissions_roles.yml", "#{dir}/permissions_roles.bkp.yml" 
    permissions = YAML.load_file("#{dir}/permissions.bkp.yml") 
    roles = YAML.load_file("#{dir}/roles.bkp.yml") 
    File.open("#{dir}/permissions.yml", 'w') do |file| 
        permissions.each do |k, v| 
            controller = v['controller'] 
            action = v['action'] 
            file.write "#{controller}_#{action}:n" 
            v.each {|key, value| file.write "  #{key}: #{value}n"} 
        end 
    end 
    File.open("#{dir}/roles.yml", 'w') do |file| 
        roles.each do |k, record| 
            file.write "#{record['name'].downcase}:n" 
            record.each {|key, value| file.write "  #{key}: #{value}n"} 
        end 
    end 

    permissions = YAML.load_file("#{dir}/permissions.yml") 
    roles = YAML.load_file("#{dir}/roles.yml") 
    prs = YAML.load_file("#{dir}/permissions_roles.bkp.yml") 
    
    File.open("#{dir}/permissions_roles.yml", 'w') do |file| 
        prs.each do |k, record| 
            permission = permissions.find_item('id', record['permission_id']) 
            role = roles.find_item('id', record['role_id']) 
            file.write "#{role}_#{permission}n" 
            record.each {|key, value| file.write "  #{key}: #{value}n"} 
        end 
    end 
end 

You can find a downloadable version here [BROKEN!]

Friday, May 26, 2006

Dump db to fixtures (generate fixtures from db)

This is a quite interesting thread on rails ml with the solution to my problem.
I wanted to generate fixtures automatically from my db. This is a rake action that does the job well. Just put it into lib/tasks/ and call it dump_fixtures.rake

desc 'Dump a database to yaml fixtures. Set environment variables DB
and DEST to specify the target database and destination path for the
fixtures. DB defaults to development and DEST defaults to RAILS_ROOT/
test/fixtures.'

task :dump_fixtures => :environment do
    path = ENV['DEST'] || "#{RAILS_ROOT}/test/fixtures"
    db   = ENV['DB']   || 'development'
    sql  = 'SELECT * FROM %s'

    ActiveRecord::Base.establish_connection(db)
    ActiveRecord::Base.connection.select_values('show tables').each do |table_name|
        i = '000'
        File.open("#{path}/#{table_name}.yml", 'wb') do |file|
            file.write ActiveRecord::Base.connection.select_all(sql %
table_name).inject({}) { |hash, record|
                hash["#{table_name}_#{i.succ!}"] = record
                hash
            }.to_yaml
        end
    end
end
# ActiveRecord::Base.connection.select_values('show tables')
# is mysql specific
# SQLite:  ActiveRecord::Base.connection.select_values('.table')
# Postgres
# table_names = ActiveRecord::Base.connection.select_values(<<-end_sql)
#    SELECT c.relname
#    FROM pg_class c
#      LEFT JOIN pg_roles r     ON r.oid = c.relowner
#      LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
#    WHERE c.relkind IN ('r','')
#      AND n.nspname IN ('myappschema', 'public')
#      AND pg_table_is_visible(c.oid)
# end_sql

Wednesday, May 17, 2006

Open in iTerm from Finder

Since I've been asked to do it, I wrote the "Open in iTerm" app, that does the very same thing than "Open in Terminal" (except that it uses iTerm instead of Terminal.app)

Actually there could be bugs, but at least on my system I suppose it's not my fault, but rather it is iTerm that crashes a lot (maybe the AppleScript part has not been tested extensively on intel macs).

If you experience problems, let me know.

The script part that accesses iTerm is

tell application "iTerm"

        activate

        set myTerm to (make new terminal)

        tell myTerm

                set mySession to (make new session at the end of sessions)

                tell mySession

                        exec command "/bin/bash"

                        write text "cd \""& myPath &"\""

                end tell

        end tell

end tell

I bundled both apps in the very same package, and you can download it here.

I upgraded this script too with Marco's help.

on run

        tell application "Finder" to try

                set myPath to quoted form of ¬

                        POSIX path of ((target of window 1) as string)

        on error

                set myPath to "~"

        end try

        

        tell application "iTerm"

                activate

                set myTerm to (make new terminal)

                tell myTerm

                        set mySession to (make new session at the end of sessions)

                        tell mySession

                                exec command "/bin/bash"

                                write text "cd "& myPath

                        end tell

                end tell

        end tell

end run

Definitive?

After some discussion on icm and the help of tv and Marco (thank you guys) we came to this

on run

tell app "Finder"

try

set myPath to quoted form of ¬

POSIX path of ((target of window 1) as string)

on error

set myPath to "~"

end

set esiste to ((count (get ¬

name of every application process ¬

whose creator type is "ITRM")) is not 0)

end

tell app "iTerm"

activate

if esiste then

set myTerm to (make new terminal)

else

set myTerm to the first terminal

end if

tell myTerm

make new session at the end of sessions

tell the last session

exec command "/bin/bash"

write text "cd "& myPath

end

end

end

end

Open in Terminal from Finder

This is a trivial AppleScript
tell application "Finder"
        set targ to target of Finder window 1
        set myPath to POSIX path of (targ as string)
end tell
tell application "Terminal" to do script "cd \""& myPath &"\""
Here you can see a couple of screenshots.
If you want to download the application (with pretty icon) that uses it, you can download it from here.
Edit: Thanks to Marco Balestra for showing me his own script (that does the same thing, but is much cleaner). Now I included his script instead of mine.
on run
        tell application "Finder" to try
                set myPath to quoted form of ¬
                        POSIX path of ((target of window 1) as string)
        on error
                set myPath to "~"
        end try
       
        tell application "Terminal"
                do script "cd "& myPath
                activate
        end tell
end run

Monday, May 1, 2006

Open with BBEdit

This is a tiny Automator Workflow that opens the current Safari document with BBEdit.
Previously I wrote an AppleScript that did the very same job, however the new document was marked as "new", thus when one tried to close it, BBEdit would complain and ask if we wanted to save
tell application "Safari"
        set cur to document 1
        set mySource to source of cur
        set myName to name of cur
end tell
tell application "BBEdit"
        set x to make new text document with properties ¬
                {contents:mySource, name:myName}
        activate
end tell
However if we use the automator action "New BBEdit Document", it offers the possibility to "Set unmodified" (that is to say the new document won't ask if it has to be saved before closing).
I created a two step Automator workflow. The first step is a slightly modified version of the first part of the script. It is a "Run AppleScript action" containing
on run {input, parameters}
        tell application "Safari"
                set cur to document 1
                set mySource to source of cur
                set myName to name of cur
        end tell
        return mySource
end run
The second step is the "New BBEdit Document" action.
You can download the workflow here. I sugest to put it in the script menu.

Sunday, April 23, 2006

Quicksort (C and Python)

The quick-sort algorithm

Quick-sort is a sorting algorithm developed by Hoare that in average does O(n log n). The O() notation means that if the list length is n, the number of operations used to sort the list is in the order of magnitudo of n log n (in this case).

To be more formal, we shall say that there exist two constants c1 and c2 such that the number of operations m isc1 * n * log n <= m <= c2 * n * log n. Notice that c1 and c2 are not specified in the O notation
We stop with math here. If you want more precise informations about the O notation read the wikipedia.

Now I'm going to briefly explain the quick-sort algorithm, and then we will use that algorithm to exploit the expressive power of some programming languages. Keep in mind that more expressive does not necessarily mean faster to run. It means faster to write. But being faster to write means that we can try more efficient algorithms, thus improving performance in a more effective way.
Expressive languages are usually high-level. In fact we can also profile the code, track the bottleneck and rewrite only a couple of functions in C or in ASM. This lead to fast programs with fast development cycles.

Quick-sort strategy

Quick-sort uses a divide and conquer approach. We divide a list in two sublists using a pivot element. All the elements less than the pivot come before it, those greater after. Then we recursively apply quick-sort to the two sublists.
Notice that the pivot is chosen arbitrarily. Some implementations chose the first element of the list. Some chose it randomly, some use other criteria.
Moreover there are implementations of quick-sort that sort the list in place (that is to say memory used is bounded), some need extra storage. Guess which are the more efficient.

On wikipedia you can find more informations about the quick-sort algorithm. You can find also some implementations, and a link to a page full of implementations in different languages.

I almost did not write code. I took code from the wikipedia or around the web and I'm going to comment it. This is the "new" work I did. Comments, explanations, not code. I also wrote a couple of implementations, however I don't remember which ones.

Python

2.4.2 (#1, Mar 23 2006, 22:00:44)  
[GCC 4.0.1 (Apple Computer, Inc. build 5250)] 

Now lets examine a Python high level implementation.

def qsort(L): 
    if L == []: return [] 
    return qsort([x for x in L[1:] if x< L[0]]) + L[0:1] + \ 
            qsort([x for x in L[1:] if x>=L[0]]) 

This is the exact description of the quick-sort algorithm, if you know what Python list comprehension are. When I write [x for x in L if p(x)], Python computer the list of elements of the L container that make p(x) true.

L[a:b] is the sublist of L[L[a], L[a+1], ..., L[b-1], L[b]]. L[a:]==L[a:len(L)], L[:b]==L[0:b]

[x for x in L[1:] if x< L[0]] is the sublist of the elements of L a part from the first one (that is the pivot) such that x is less than the pivot (L[0]).

[x for x in L[1:] if x>=L[0]] is the sublist of the elements of L a part from the first one (that is the pivot) such that x is greater or equal than the pivot (L[0]).

Then we pass those sublists to qsort that recursively sorts them, and eventually we return a append all those sublists and return them.

This implementation, although beautiful to read and understand is horrible from a performance point of view. It creates, concatenates and destroys a large number of lists. Moreover it is purely recursive. For large lists, we can even exhaust the stack space.

A version of quick-sort in Python that has no need for more memory is this:

def partition(array, begin, end, cmp): 
    while begin < end: 
        if cmp(array[begin], array[end]): 
            (array[begin], array[end]) = (array[end], array[begin]) 
            break 
        end -= 1 
    while begin < end: 
        if cmp(array[begin], array[end]): 
            (array[begin], array[end]) = (array[end], array[begin]) 
        break 
        begin += 1 
    return begin 
    
    def sort(array, cmp=lambda x, y: x > y, begin=None, end=None): 
        if begin is None: begin = 0 
        if end   is None: end   = len(array) 
        if begin < end: 
            i = partition(array, begin, end-1, cmp) 
        sort(array, cmp, begin, i) 
        sort(array, cmp, i+1, end) 

[NOTE: code has been reformatted without running it again: it is likely
to be wrong!]

If you want to run this code, remember that in Python indentation matters. If you just copy and paste the code, you may end with unusable code.
Anyway, I benchmarked all of them. "Elegant quicksort" is the first implementation. "Standard quicksort" is the latter. "Bultin sort" is standard python sort algorithm (that is not a quicksort, but a dedicated sorting algorithm).

Elegant qsort: [21.20, 19.75, 20.08, 20.46]
Builtin qsort: [1.61, 2.29, 2.29, 2.29]
Standard qsort: [31.15, 30.60, 30.68, 30.38]

Probably due to heavy optimization performed in list comprehension the "elegant" algorithm is faster than the standard one. [from the future: I hardly believe that]. However both of them are more than ten times slower than the python built-in sort algorithm.
We have learnt:

  1. High level languages are great to express algorithms in a readable way (and we can use them to test them and see how they work and all)
  2. You should not implement "basic" algorithms in high level languages: use their built-ins or write them in C (most built-ins are written in C).

C

Now it is time for a couple of pure C quick-sort:

void qsort1(int a[], int lo, int hi ){ 
    int h, l, p, t; 
    if (lo < hi) { 
        l = lo; 
        h = hi; 
        p = a[hi]; 
        do { 
            while ((l < h) && (a[l] <= p))  
                l = l+1; 
            while ((h > l) && (a[h] >= p)) 
                h = h-1; 
            if (l < h) { 
                t = a[l]; 
                a[l] = a[h]; 
                a[h] = t; 
            } 
        } while (l < h); 
        t = a[l]; 
        a[l] = a[hi]; 
        a[hi] = t; 
        qsort( a, lo, l-1 ); 
        qsort( a, l+1, hi ); 
    } 
} 

Another implementation is:

void quicksort(int x[], int first, int last) { 
    int pivIndex = 0; 
    if(first < last) { 
        pivIndex = partition(x,first, last); 
        quicksort(x,first,(pivIndex-1)); 
        quicksort(x,(pivIndex+1),last); 
    } 
} 

int partition(int y[], int f, int l) { 
    int up,down,temp; 
    int piv = y[f]; 
    up = f; 
    down = l; 
    goto partLS; 
    do {  
        temp = y[up]; 
        y[up] = y[down]; 
        y[down] = temp; 
        partLS: 
        while (y[up] <= piv && up < l) { 
         up++; 
        } 
        while (y[down] > piv  && down > f ) { 
            down--; 
        } 
    } while (down > up); 
    y[f] = y[down]; 
    y[down] = piv; 
    return down; 
} 

C also have a builtin quick-sort, that is much more advanced than this ones, since it allows to specify a comparison function, thus working with all kinds of data types.

Benchmarking these was hard. They too fast to be benchmarked with a list of a million elements and the standard posix clock function. However if you want to run the bench yourself, I could not use MacOS X specific bench functions.
So I used a list of 100000000 elements.
This is the (ugly) code I used for benchmarking. The test is not really interesting. Of course since C integers are machine integers it is dramatically faster than other solutions. It could have been more interesting if we sorted other data structures, where the gap could be reduced.

#include <stdlib.h> 
#include <stdio.h> 
#include <time.h> 
#include "qsort1.h" 
#include "qsort2.h" 
#define LEN 100000000 

int intcmp(const void *a, const void *b){ 
    return *(int*)a - *(int*)b; 
} 

int main(){ 
    size_t index; 
    int *l = malloc(sizeof(int)*LEN); 
    clock_t last, current; 
    srand(time(NULL)); 
    for(index = 0; index < LEN; ++index){ 
        l[index] = rand(); 
    } 
    
    last = clock(); 
    qsort(l,LEN, sizeof(int), intcmp); 
    current = clock(); 
    printf("C qsort: %f\n", (current-last)/(float)CLOCKS_PER_SEC); 
    
    for(index = 0; index < LEN; ++index){ 
        l[index] = rand(); 
    } 
    last = clock(); 
    qsort1(l,0, LEN-1); 
    current = clock(); 
    printf("int qsort: %f\n", (current-last)/(float)CLOCKS_PER_SEC); 
    for(index = 0; index < LEN; ++index){ 
        l[index] = rand(); 
    } 
    last = clock(); 
    quicksort(l,0, LEN-1); 
    current = clock(); 
    printf("qsort 2: %f\n", (current-last)/(float)CLOCKS_PER_SEC); 
    free(l); 
    return 0; 
} 

Friday, April 21, 2006

Something about Prolog...

As I had to admit in my last Prolog post, I'm no Prolog guru. I'd rather deserve the term newbie. However, I followed some math logic courses that make it all less harder. If you find something incorrect or if you don't understand something, comment it.

The first thing you have to keep in mind is that you don't really tell Prolog how to do something. You rather ask "him" (or her?) to prove something following the rules you gave.

Basic datatypes

In Prolog we have "Strings". We can also use terms like string or dog. However if they have capital letter, they are
variables, not simple terms.
We have list that is to say [], [a, b, c]. If we write
[H | T] H is the first element of the list, T a list containing all the remaining elements. If the list is [a, b, c], H is a and T is [b, c]

Computation model

Relations

Suppose you are working with a graph. Now suppose that you want to query the graph. As an example I report here a graph about elven genealogy in the LOTR world.The schema comes from this site. If it is wrong, tell them, not me :)

For example there are different interpretation regarding Indis. Some say she's Ingwë's sister, some say she's the daughter of Ingwë's sister. We chose to say she's Ingwë's sister since I do not want to introduce a character with no name in our database :).

The House of Finarfin:

                + - - - - - +
                :         Ingwë
             (sister)  + - - - - - +
                |      |           |
      Finwë = Indis   Olwë       Elwë = Melian
            |           |             |
          Finarfin = Ëarwen          Luthien
                   |
  +----------------+----------------+---------+
  |                |                |         |
  |                |              Aegnor      |
Finrod = Amarië Angrod = Edhellos    Galadriel = Celeborn
         :                |                         |
  (descendants        Orodreth          Elrond = Celebrian
     in Aman?)            |                    |
                  +-------+------+      +------+---------+
                  |              |      |      |         |
               Gil-galad    Finduilas Elladan Elrohir  Arwen

How would we represent this in an imperative language? We probably would have some kind of

class Elf 
- gender   (M/F) 
- name     (String) 
- children (Elven) 
- partner  (Elf) 
end 

We could also have a kind of "double linked structure". This is probably wise since otherwise querying someone's father would be dramatically expensive.

class Elf 
- gender   (M/F) 
- name     (String) 
- children (Elven) 
- partner  (Elf) 
- mother   (Elf) 
- father   (Elf) 
end 

In prolog we do not have such structure. We just tell "facts". A fact is a predicate that is always true. You can see how we define facts above. For example we are saying that aegnor is male.

male(aegnor). 
male(angrod). 
... 

You can imagine this like

Elf Aegnor;Aegnor.name = "Aegnor";Aegnor.gender = M;... 

Note that in Prolog everything is a Term, both data and program. Above I'm saying that aegnor is male. I assert that male(aegnor) is true.
This is the complete list of facts to define the above graph. If I were smarter I chose a smaller graph. However the list is long, but the imperative code to put into memory would not have been significantly shorter (yes, we could read it from file... where we would have had a list similar to the prolog version, :) )

female(amarie). 
female(arwen). 
female(celebrian). 
female(earwen). 
female(edhellos). 
female(finduilas). 
female(galadriel). 
female(indis). 
female(luthien). 
female(melian). 
male(aegnor). 
male(angrod). 
male(celeborn). 
male(elladan). 
male(elrohir). 
male(elrond). 
male(elwe). 
male(finarfin). 
male(finrod). 
male(finwe). 
male(gilgalad). 
male(ingwe). 
male(olwe). 
male(orodreth). 
parent(ingwe, olwe). 
parent(ingwe, elwe). 
parent(indis, finarfin). 
parent(finwe, finarfin). 
parent(olwe, earwen). 
parent(elwe, luthien). 
parent(melian, luthien). 
parent(finarfin, finrod). 
parent(earwen,   finrod). 
parent(finarfin, angrod). 
parent(earwen,   angrod). 
parent(finarfin, aegnor). 
parent(earwen,   aegnor). 
parent(finarfin, galadriel) . 
parent(earwen,   galadriel) . 
parent(angrod, orodreth). 
parent(edhellos, orodreth). 
parent(galadriel, celebrian). 
parent(celeborn, celebrian). 
parent(orodreth, gilgalad). 
parent(orodreth, finduilas). 
parent(elrond,    elladan). 
parent(celebrian, elladan). 
parent(elrond,    elrohir). 
parent(celebrian, elrohir). 
parent(elrond,    arwen). 
parent(celebrian, arwen). 

Rules

A rule is in the form:

goal(X) :- subgoal(X), subgoal2(X). 

In the above goal(X) is true if and only if both subgoal(X) and subgoal2(X) are true. We say we reducegoal to the two subgoals.
We will query something like:

goal(elrond). 

and it will succeed if and only if both subgoal(elrond) and subgoal2(elrond). Notice this times we have constants and not variables.
Now it is time to define some interesting relation. A father is a male parent. A mother a female parent. In Prolog we write:
father(X, Y) :- parent(X, Y), male(X). 
That is to say... X is father of Y if and only if X is parent of Y and X is male.
If we want to find Orodreth father, we query:
father(X, orodreth). 
If is succeeds (and it does) in X there is Orodreth's father: Angrod. The imperative version of this would have been... orodreth.father. If we were wise enought (or had enough space) to use a double linked structure. If we didn't, well... we would have to traverse the graph.
We can also do the converse.
father(finarfin, X). 
would return all the children of finarfin.

mother(X, Y) :- parent(X, Y), female(X). 
son(X, Y)    :- parent(Y, X), male(X). 
daughter(X, Y)  :- parent(Y, X), male(X). 

These are other trivial relationship. Now suppose you want to find out all the ancestors of a given character. If you had the simpler structure, it is a pain in the ass. If you have the complete one, it is boring. Basically you have to tell the system to traverse the graph following father and mother links. Simple and tedious.
In fact what you are doing is the "transitive closure" of the parent relationship. In Prolog it is exactly how define in natural language. X is ancestor of Y if X is parent of Y or if X is parent of Z and z is ancestor of Y.

ancestor(X, Y) :- parent(X, Y). 
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y). 

All this relationships can be used to find the ancestors or the grandchildren. Or to verify if the relationship holds between two elves.
mother(galadriel, celebrian). returns yes, while mother(galadriel, arwen). returns no. You have to distinguish between defining facts and relationships and querying the system. This depends from your prolog interpreter: read a book, a tutorial, something. This is just a hint (and what I need to explain quicksort later on).
If you name this file elves.pl you can load it in swi-prolog with

[elves]. 

(remeber, no extention and end with a dot). Then you can just make queries. To define new predicates, put them in elves.pl and reload the file.

Some arithmetic...

We can consider the trivial algorithm to sum two numbers, provided we have an
INC and a DEC operation.
VAR A, B 
WHILE B > 0 
INC A 
DEC B 
END 

This is quite obvious. If you (like me) hate those pseudo code examples, this is pure C.

unsigned int sum(unsigned int a, unsigned int b){ 
    while(b) { 
        ++a; --b; 
    } 
    return a; 
} 
It is quite interesting an example in a functional programming. This resembles the basic definition of addition if you are working with primitive recursive functions (S is the successor function and we omitted to write explicitly the i-th projection function).

sum( x, 0   ) = x 
sum( x, y+1 ) = S(sum(x, y))

And this is Haskell (almost the same thing, a part from notations).

mysum :: Int -> Int -> Int 
mysum x 0 = x 
mysum x y = mysum x (y-1) + 1 

In Prolog once again you follow the formal definition of sum in Set Theory. (That by the way is quite the same as above).

add(X, 0, X).add(0, Y, Y).add(X, Y, X1) :- succ(Y1, Y), add(X, Y1, X2), succ(X2, X1). 

How this works? When I query something with add prolog will try to "match" against the arguments of the main goal. I don't want to be more precise about this "matching". It is called unification, and you are supposed to read a prolog tutorial to understand more about it.
add(5, 0, 5). will match the first rule: the second parameter is 0, and the other two are the very same term. Now let's consideradd(0, 5, X). . This could match the second rule. 0 matches 0. 5 matches Y. From this point for add to succeed, X must be 5 too. From swi-prolog:

2 ?- plus(0, 5, X). 
X = 5  
Yes 

However, we said that we expect to use Prolog predicates in many different ways. Not only to sum two numbers, but also to find if given three numbers the third is the sum of the first two. We expect also that trivial predicates can be inverted. That is to say given a number and the "sum" find the number that summed to the first one gives the sum.
That is to say we expect to have the subtraction defined by only defining the sum. In fact this ain't magic. Prolog builtin plus predicate does exaclty this.
This is a copy and paste from the swi prolog terminal:

31 ?- plus(X, 4, 7). 
X = 3  
Yes 
32 ?- plus(8, 9, Z). 
Z = 17  
Yes 
33 ?- plus(3, Y, 1). 
Y = -2  
Yes 

For those of you who are interested, we can define such a predicate this way, using builtin prolog arithmetic and some metalogical variables:

add(X, Y, Z) :- nonvar(X), nonvar(Y), Z is X+Y . 
add(X, Y, Z) :- nonvar(X), nonvar(Z), Y is Z-X . 
add(X, Y, Z) :- nonvar(Y), nonvar(Z), X is Z-Y . 

nonvar returns true if and only if its argument is not a variable. That is to say, if instead of plus we used add, add(X, 4, 7). would have called the "third" predicate (for Y and Z are not variables, since they are "unified" -- substituted -- with 4 and 7). add(8, 9, Z). would have called the first predicate and add(3, Y, 1) the second.

But we can do something even smarter. First of all we recognize that the three clauses above are almost mutually exclusive. Two of the three clauses will fail if two of the three parameters are not variables. They will all succeed in the very same way if all three are not variables. They will all fail if only one is a variable.

So we can tell prolog: after you determined which is the variable, you can only use that rule. If none is a variable, use the first rule. We use "cuts". The rules become.

add(X, Y, Z) :- nonvar(X), nonvar(Y), !, Z is X+Y . 
add(X, Y, Z) :- nonvar(X), nonvar(Z), !, Y is Z-X . 
add(X, Y, Z) :- nonvar(Y), nonvar(Z), !, X is Z-Y . 

Cuts are a complex subject. I'm not going to treat them here. Now I introduce a predicate between.


between(+Low, +High, ?Value)
Low and High are integers, High >=Low. If Value is an integer,
Low=< Value=< High. When Value is a variable it is successively
bound to all integers between Low and High. If High is inf
or infinite between/3 is true iff Value>= Low, a feature that is
particularly interesting for generating integers from a certain
value.

At this point we add this clauses:
add(X, Y, Z) :- nonvar(Z), !, between(0, Z, X), add(X, Y, Z). 
add(X, Y, Z) :- nonvar(Y), !, between(0, inf, X), add(X, Y, Z). 
add(X, Y, Z) :- nonvar(X), !, between(0, inf, Y), add(X, Y, Z). 

Now you are able given one variable to generate pairs that satisfy the relationship (in fact pairs of positive numbers only).
Now let define prod.

prod(X, Y, Z) :- nonvar(X), nonvar(Y), !, Z is X*Y . 
prod(X, Y, Z) :- nonvar(X), nonvar(Z), !, Y is Z/X . 
prod(X, Y, Z) :- nonvar(Y), nonvar(Z), !, X is Z/Y . 
prod(X, Y, Z) :- nonvar(Z), !, between(1, Z, X), prod(X, Y, Z). 
prod(X, Y, Z) :- nonvar(Y), !, between(1, inf, X), prod(X, Y, Z). 
prod(X, Y, Z) :- nonvar(X), !, between(1, inf, Y), prod(X, Y, Z). 

Now it's time to define division. Do you know the euclidean algorithm? I suppose so. However, you don't need to know it. All you need to know is that dividing x for y you are looking for two numbers q and r such that

  • x = y * q + r
  • 0 <= r < y>

And in Prolog it is:

div(X, Y, 0, X) :- abs(X) < abs(Y). 
div(X, Y, Q, R) :- prod(Y, Q, T1), T1 =< X,  add(T1, R, X) , 
                   R >= 0, abs(R) < abs(Y). 

This does not work when X and Y have not the same sign. However this depends from the way I defined prod. You should be able to make it work.

Monday, April 10, 2006

Texniscope Intel

I have just compiled a Texniscope version for Intel.

It works for me, tell me if it works for you too.

Download

[BROKEN LINK!] If you really need this, email me, I will search it on my hard drive.

Saturday, April 8, 2006

Autoconf automake & libtool on MacOS X

I have just finished my first autotools project on the MacOS. Until today I deployed software only in Python or Java. I already worked on C and C++ projects that used libtool and automake and autoconf, but I had not to write the configure scripts myself or I developed them on GNU/Linux.

In fact I'm afraid most of the problems I encountered was MacOS X fault + my ignorance. That is to say libtoolize does not exist: it is called glibtoolize. So if I do not rename it, autoreconf simply does not work.

Probably I just had to set the LIBTOOLIZE environment variable to glibtoolize. However my solution works. The error I got was

Can't exec "libtoolize": No such file or directory at /opt/local/share/autoconf/Autom4te/FileUtils.pm line 288, <GEN3> line 3.

autoreconf: failed to run libtoolize: No such file or directory

Well... I've to fine tune it. I go.

Wednesday, April 5, 2006

Multitasking on MacIntel

I noticed changing the subject also changes the link. So I repost this to redirect you to the new article.

I also have a more recent test that quite leads to other conclusions