November 15, 2014

Mengakses Engine Prolog (tuProlog) dari Scala

Prolog merupakan bahasa pemrograman komputer generasi awal, dibuat oleh Alain Colmerauer pada sekitar awal tahun 1970-an dan dikembangkan oleh Alain bersama dengan Phillipe Roussel pada tahun 1972. Prolog pada awalnya memang dikembangkan untuk aplikasi AI (Artificial Intelligence) dengan kekhususan pada formalisme linguistik. Prolog banyak digunakan pada berbagai universitas dan pendidikan tinggi dan seakan-akan jauh dari industri meskipun banyak cerita kesuksesan dari Prolog (misalnya penggunaan Sicstus Prolog atau SWI Prolog). Di Indonesia, bisa dibilang Prolog memang murni masih berada di "dunia imajinasi" karena hanya digunakan pada banyak mata kuliah di berbagai perguruan tinggi tetapi jauh dari dunia industri (as always, CMIIW).

Saat ini Prolog mulai banyak dikembangkan untuk aplikasi tingkat lanjut karena kemampuan internal dari bahasa pemrograman tersebut yang sesuai untuk pemecahan masalah kompleks yang melibatkan reasoning serta berbagai fasilitas lainnya yang sesuai untuk keperluan aplikasi terdistribusi di Intenet (DCG untuk parsing dan menghasilkan list, pemrosesan data, declarative programming untuk komunikasi dan interaksi agent, dan lain-lain). Interpreter dan compiler Prolog juga banyak dikembangkan dan tersedia untuk berbagai platform. Untuk tulisan ini kita akan menggunakan tuProlog. tuProlog merupakan sistem Prolog yang dikembangkan untuk Java (dan .NET). Hal yang menarik dari tuProlog, sistem ini menyediakan sistem Prolog yang ringan dan hanya mengkonsentrasikan diri pada fitur standar (ISO Prolog) sedangkan bagian lainnya bisa menggunakan Java. Untuk artikel ini kita akan menggunakan Scala yang merupakan bahasa obyek-fungsional untuk aplikasi yang dijalankan di atas JVM.

Untuk mengikuti artike ini, ada beberapa yang harus dipersiapkan:

  1. Install JDK (saya menggunakan versi 1.8.0_25)
  2. Install Scala (saya menggunakan versi 2.11.4)
  3. Download tuProlog (saya menggunakan versi 2..9.1)
  4. Hmm ... saya menggunakan Linux - bash, jika anda menggunakan tools selain itu silahkan buat penyesuaian sendiri.


Artikel ini hanya menjelaskan cara mengakses Prolog engine melalui Scala. Setelah memahami artikel ini, anda bisa menggunakan fitur dari sistem tuProlog, menuliskan kode Prolog yang dijalankan melalui tuProlog dan kemudian menjalankan engine Prolog melalui Scala sekaligus mengambil hasil dari hasil eksekusinya. Untuk artikel ini, kita belum menggunakan sbt sehingga setting CLASSPATH harus dilakukan secara manual. Artikel menggunakan sbt semoga bisa segera menyusul.

Copy file 2p.jar dan tuprolog.jar

$ ls
total 744
drwxr-xr-x  2 bpdp bpdp   4096 Nov 16 08:04 .
drwxr-xr-x 19 bpdp bpdp   4096 Nov 16 07:58 ..
-rw-r--r--  1 bpdp bpdp 547424 Nov 16 08:00 2p.jar
-rw-r--r--  1 bpdp bpdp    392 Nov 16 08:04 HelloProlog.scala
-rw-r--r--  1 bpdp bpdp 198340 Nov 16 08:00 tuprolog.jar
$


Setting CLASSPATH

$ export CLASSPATH=$CLASSPATH:.:2p.jar:tuprolog.jar
$


Kode Sumber

File Scala berikut ini (HelloProlog.scala) saya terjemahkan dari manual untuk kode sumber Java hal 166. Interoperabilitas Scala dan Java sangat bagus sehingga penggunaan tuProlog engine berjalan dengan baik dan kode sumber Scala relatif lebih mudah dipahami.


import alice.tuprolog._
import scala.util.control._

object HelloProlog {

  def main(args: Array[String]) {

    val pEngine = new Prolog
    var info = pEngine.solve("append(X,Y,[1,2]).")
    val loop = new Breaks

    loop.breakable {
      
      while (info.isSuccess()) {

        println("solution: " + info.getSolution() + 
          " - bindings: " + info)
        if (pEngine.hasOpenAlternatives()) {
          info = pEngine.solveNext()
        } else {
          loop.break
        }

      }

    }

  }

}


Penggunaan tuProlog engine sesederhana mendefinisikan engine Prolog (new Prolog) dan kemudian menggunakan method solve untuk mengeksekusi kode sumber Prolog.

Kompilasi

$ scalac HelloProlog.scala
$ ls -la
total 756
drwxr-xr-x  2 bpdp bpdp   4096 Nov 16 08:43 .
drwxr-xr-x 19 bpdp bpdp   4096 Nov 16 07:58 ..
-rw-r--r--  1 bpdp bpdp 547424 Nov 16 08:00 2p.jar
-rw-r--r--  1 bpdp bpdp   1930 Nov 16 08:16 HelloProlog$$anonfun$main$1.class
-rw-r--r--  1 bpdp bpdp    657 Nov 16 08:16 HelloProlog.class
-rw-r--r--  1 bpdp bpdp   1140 Nov 16 08:16 HelloProlog$.class
-rw-r--r--  1 bpdp bpdp    520 Nov 16 08:16 HelloProlog.scala
-rw-r--r--  1 bpdp bpdp 198340 Nov 16 08:00 tuprolog.jar
$


Running

$ scala HelloProlog
solution: append([],[1,2],[1,2]) - bindings: yes.
X / []  Y / [1,2]
solution: append([1],[2],[1,2]) - bindings: yes.
X / [1]  Y / [2]
solution: append([1,2],[],[1,2]) - bindings: yes.
X / [1,2]  Y / []


Menggunakan tuProlog akan memungkinkan aplikasi kita menggunakan berbagai fitur AI yang bermanfaat untuk memperbaiki kinerja software yang kita aplikasikan. Happy hacking!

Mei 23, 2014

Maven repository priority in Gradle

If you get an error like this when you execute gradle build, it means that there is something wrong with your maven repository priority (just an example):

Checksum missing at http://www.systap.com/maven/releases/org/semanticweb/yars/nxparser/1.2.3/nxparser-1.2.3.pom.sha1 due to: For input string: "<!"
Download http://www.systap.com/maven/releases/org/semanticweb/yars/nxparser/1.2.3/nxparser-1.2.3.pom
[Fatal Error] nxparser-1.2.3.pom:2:10: Already seen doctype.


Below is a snapshot of my build.gradle:


    // maven repo for BigData - as embedded RDF database
    // we are looking for BigData with Blueprints also
    // needed by BigData: nxparser
    maven { url "http://www.systap.com/maven/releases" }
    maven { url "http://nxparser.googlecode.com/svn/repository" }



My BigData repository need nxparser, but the problem is, maven repo for nxparser reside after BigData repo, so gradle doesn't know that it has to fetch nxparser from repository below. Change the order into this to fix the problem:


    // maven repo for BigData - as embedded RDF database
    // we are looking for BigData with Blueprints also
    // needed by BigData: nxparser
    maven { url "http://nxparser.googlecode.com/svn/repository" }
    maven { url "http://www.systap.com/maven/releases" }



April 13, 2014

Gradle Untuk Mengelola Repo Lokal Maven

Saat pertama kali menggunakan Gradle, saya cukup kerepotan mempelajari tool ini karena dokumentasinya lebih mirip dengan manual. Tantangan yang pertama saya peroleh adalah menggunakan repository maven di komputer saya karena kadang kala software yang saya kembangkan berupa API (Application Programming Interface). Keinginan saya sederhana:

  1. Develop pustaka (API)
  2. Kompilasi dan build API dalam format .jar
  3. Push .jar ke repositori lokal maven (API, Javadoc, dan source code)
  4. API (.jar) di repositori lokal tersebut siap digunakan untuk pengembangan software berikutnya

Membaca manual Gradle cukup merepotkan untuk hal sederhana tersebut, jadi saya akan uraikan cara sederhana untuk keperluan tersebut. Pada dasarnya ada 3 file yang akan banyak digunakan:

  1. build.gradle di proyek pustaka API
  2. gradle.properties untuk berbagai properties yang diperlukan di proyek pustaka API
  3. build.gradle di proyek yang akan menggunakan file .jar tersebut

build.gradle di proyek pustaka API

Perhatikan, plugin yang digunakan adalah 'maven'. Perhatikan juga di bagian bawah mulai dari bagian untuk mengkonfigurasi POM.


apply plugin: 'java'
apply plugin: 'maven'

sourceCompatibility = '1.8'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'


repositories {

 mavenLocal()
 mavenCentral()

 maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }

 // definisi URL utk repo lainnya ...
  
}

dependencies {

 // contoh dependency untuk compile
 compile group: 'com.bigdata', name: 'bigdata', version: '1.3.0'
 
 // dependency untuk test                     
 testCompile group: 'junit', name: 'junit', version: '4.10'

}

test {

 /* Configure which tests are included
 include 'org/foo/**'
 exclude 'org/boo/**'
 */

 maxParallelForks = 5
 maxHeapSize = '1024m'

}

// bagian ini ke bawah yang penting untuk mengkonfigurasi POM

configure(install.repositories.mavenInstaller) {
 pom.project {
  groupId 'name.bpdp'
  artifactId 'turgo'
  inceptionYear '2014'
  packaging 'jar'
  licenses {
   license {
    name 'Eclipse Public License (Version 1.0)'
    url 'http://www.eclipse.org/legal/epl-v10.html'
    distribution 'repo'
   }
  }
 }
}

// untuk sources.jar
task sourcesJar(type: Jar, dependsOn:classes) {
 classifier = 'sources'
 from sourceSets.main.allSource
}

// untuk javadoc.jar
task javadocJar(type: Jar, dependsOn:javadoc) {
 classifier = 'javadoc'
 from javadoc.destinationDir
}

// artifacts yang di-push selain .jar API
artifacts {
 archives sourcesJar
 archives javadocJar
}

gradle.properties

Berisi properties dari proyek. Isinya adalah sebagai berikut:

version=0.0.1
group=name.bpdp.turgo

Perhatikan, tidak boleh menggunakan tanda petik string untuk value karena akan menyebabkan error di task javadoc:

Illegal package name: "0.0.1"
Illegal package name: " API"

Error ini seringkali membingungkan karena tidak jelas, jadi jika menemui error seperti itu, periksa gradle.properties.

Setelah itu, task "install" ($ gradle install) akan mem-build API, menghasilkan .jar, menghasilkan .jar untuk javadoc dan sources, kemudian mem-push semua .jar ke repo lokal seperti berikut ini:

build.gradle di proyek yang akan menggunakan .jar

Sederhana saja, jika sudah di-push, tinggal cantumkan mavenLocal() di repositories dan deklarasikan dependency compile untuk .jar tersebut. Berikut ini adalah contohnya:

pply plugin: 'java'
apply plugin: 'application'

sourceCompatibility = 1.8
version = '1.0'

mainClassName = 'turgo.examples.hello.HelloTurgo'

repositories {

 mavenLocal()
 mavenCentral()

 maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }

}

dependencies {
 compile group: 'name.bpdp', name: 'turgo', version: '0.0.1'
 testCompile group: 'junit', name: 'junit', version: '4.11'
}

That's all there is to say. :)