Tuesday, August 18, 2015

Tutorial Data Binding di JavaFX

Dalam tutorial kali ini saya akan memberikan  contoh bagaimana menggunakan konsep data binding di JavaFX. Sebenarnya ini terinspirasi dari sebuah kursus yang saya ikuti kemarin mengenai penggunaaan WPF (Windows Presentation Foundation) yang konsepnya juga hampir mirip dengan JavaFX.

Defenisi data binding sendiri adalah bagaimana perubahan yang dialami oleh sebuah element UI (misalnya button) langsung direfleksikan pada elemen UI yang lain (misalnya panel atau window). Jadi ketika kita merubah lebar button, maka lebar panel secara serta merta ikutan berubah. Dalam konsep  UI jadul, misalnya yang dijumpai pada Jawa Swing, hal ini amat rumit untuk diaplikasikan. Bisa sih, namun kode yang kita buat agak kotor. Kita mungkin bisa mendeteksi event click mouse yang dilakukan pada sebuah button atau event mouse drag. Namun bagaimana kalau sudah hal-hal semisal perubahan property lebar atau tinggi button tersebut, tentu cukup sulit untuk mendeteksinya. Salah satu cara kotor untuk menempuhnya antara lain dengan membuat sebuah thread yang secara periodik mengecek perubahan pada ukuran button tersebut untuk kemudian merefleksikannya pada panel.

Pada WPF, teknik data binding biasanya dilakukan secara langsung pada XAML. Namun kemudian saya menyadari bahwa cara ini kurang tepat. Hal ini karena  antara property-property yang di-binding biasanya tidak proporsional nilainya. Misalnya jika kita mem-binding lebar button dengan lebar panel (atau window), tentu itu kurang tepat karena secara umum lebar button jauh lebih kecil dari lebar panel. Jadi kita harus melakukan operasi aritmatika di situ. Misalnya dengan mengeset lebar button setengah atau seperempat dari lebar window.

Masalahnya adalah kita tidak bisa menyertakan operasi aritmatika ke dalam file XAML (atau sebut saja XML). Jadi mau tidak mau kita harus letakkan pengesetan tersebut pada code behind-nya. Dan ini sudah diantisipasi oleh JavaFX.

Jadi dalam JavaFX tersebut sebuah UI element (misalnya window) properti propertynya sudah mengantisipasi adanya event yang terjadi. Dalam Java Swing, sebuah window (atau dalam terminologinya disebut sebagai JFrame) hanya memiliki width atau height saja. Dalam JavaFX, sebuah window (atau dalam terminologinya disebut sebagai Stage) width dan height nya itu sudah berubah menjadi widthProperty dan heightProperty yang bisa diberikan listener jika terjadi sebuah event. Perhatikan video berikut.



Dalam video di atas, jelas bahwa lebar button tidak mungkin di binding secara langsung dengan lebar window, akan tetapi harus dikalikan sebuah rasio tertentu.

Video berikut ini sebuah contoh bagaimana di JavaFX terdapat objek khusus yakni objek text yang tidak dijumpai pada WPF.

package fjr.test.binding;

import javafx.application.Application;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TestBindingButton extends Application{

 Stage prStage; 
 
 Button testButton; 
 
 @Override
 public void start( Stage primaryStage) throws Exception {
  
  AnchorPane pane = new AnchorPane();
  
  Scene sc  = new Scene(pane, 500, 400) ; 
  
  primaryStage.setScene(sc); 
  
  primaryStage.show();
  
  this.prStage = primaryStage; 
  
  getChildren(pane);
  
  primaryStage.widthProperty().addListener(new InvalidationListener() {
   
   @Override
   public void invalidated(Observable arg0) {
    testButton.setPrefWidth(prStage.getWidth()/3.0) ;
    testButton.setPrefHeight(prStage.getHeight()/10.0);
   }
  });
   
 }
 
 
 private void getChildren(Pane p){
  
  VBox box1 = new VBox(); 
  box1.setSpacing(5);
  box1.setTranslateX(10);
  box1.setTranslateY(10);
  
  
  final Button b1 = new Button("COBA"); 
  b1.setPrefWidth(prStage.getWidth()/3.0) ;
  b1.setPrefHeight(prStage.getHeight()/10.0);  
  box1.getChildren().add(b1); 
  
  
  final Button b2 = new Button("ACUAN"); 
  b2.setPrefWidth(prStage.getWidth()/3.0) ;
  b2.setPrefHeight(prStage.getHeight()/10.0);  
  box1.getChildren().add(b2); 
  
  this.testButton = b1; 
  
  p.getChildren().addAll(box1); 
 }
 
 public static void main(String[] args){
  launch(args);
 }
}
package fjr.test.binding;

//import java.awt.Button;
import java.util.Random;

import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Orientation;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.text.Font;
import javafx.scene.text.FontPosture;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;


public class TestBindingFont extends Application{
 
    private static final Random RANDOM = new Random();
    private static final Interpolator INTERPOLATOR = Interpolator.SPLINE(0.295,0.800,0.305,1.000);
    Pane p; 
    
    Font font = new Font (Font.getDefault().getFamily(), 60 ) ; 

 @Override
 public void start(Stage primaryStage) throws Exception {
  // TODO Auto-generated method stub
  
  final AnchorPane pane = new AnchorPane(); 
  Scene sc = new Scene(pane, 500,500 ); 
  
  primaryStage.setScene(sc);
  primaryStage.show(); 
  
  pane.setFocusTraversable(true); 
  pane.setOnMousePressed(new EventHandler() {
   @Override
   public void handle(MouseEvent me) {
    pane.requestFocus();
    me.consume();
   }
  });
  
  pane.setOnKeyPressed(new EventHandler() {
   @Override
   public void handle(KeyEvent ke) {
    createLetter(ke.getText()); 
    ke.consume();
   }
  });
  
  p = pane; 
  
  final Slider s = new Slider(); 
  s.setTranslateX(10); 
  s.setTranslateY(10); 
  s.setPrefWidth(150); 
  s.setOrientation(Orientation.HORIZONTAL);
  s.setMin(1); 
  s.setMax(10); 
  s.valueProperty().addListener(new InvalidationListener() {   
   @Override
   public void invalidated(Observable arg0) {
    double m = s.getValue(); 
    Font f2  = new Font(Font.getDefault().getFamily(), 60 * m); 
    font = f2; 
    for( Node  t : p.getChildren()){
     if(t instanceof Text){
      Text tt = (Text) t; 
      tt.setFont(f2);
     }
     
    }
   }
  });
  
  VBox box = new VBox(); 
  box.setSpacing(5); 
  
  pane.getChildren().add(box);
  box.getChildren().add(s); 
  
  Text t  = new Text("Ketikan sesuatu di Keyboard!!"); 
  t.setTranslateX(10);
  t.setTranslateY(20); 
  Font f = Font.font(Font.getDefault().getFamily(), FontWeight.BOLD , FontPosture.ITALIC , 20); 
  
  t.setFont(f); 
  
  box.getChildren().add(t);  
  
  t.setFill( new LinearGradient(0f,1f,1f,0f,true, CycleMethod.NO_CYCLE, 
      new Stop(0,Color.web("#f8bd55")),
                        new Stop(0.14f,Color.web("#c0fe56")),
                        new Stop(0.28f,Color.web("#5dfbc1")),
                        new Stop(0.43f,Color.web("#64c2f8")),
                        new Stop(0.57f,Color.web("#be4af7")),
                        new Stop(0.71f,Color.web("#ed5fc2")),
                        new Stop(0.85f,Color.web("#ef504c")),
                        new Stop(1,Color.web("#f2660f"))));

 }
 
  private void createLetter(String c) {

         final Text letter = new Text(c);
         letter.setFill(Color.BLACK);
         letter.setFont(font);
         letter.setTextOrigin(VPos.TOP);
         letter.setTranslateX((p.getWidth() - letter.getBoundsInLocal().getWidth()) / 2);
         letter.setTranslateY((p.getHeight() - letter.getBoundsInLocal().getHeight()) / 2);

         p.getChildren().add(letter);

         final Timeline timeline = new Timeline();
         timeline.getKeyFrames().add(
                 new KeyFrame(Duration.seconds(6), new EventHandler() {
                     @Override public void handle(ActionEvent event) {
                         p.getChildren().remove(letter);
                     }
                 },
                 new KeyValue(letter.translateXProperty(), getRandom(0.0f, p.getWidth() - 
                   letter.getBoundsInLocal().getWidth()),INTERPOLATOR),
                 new KeyValue(letter.translateYProperty(), getRandom(0.0f, p.getHeight() - 
                   letter.getBoundsInLocal().getHeight()),INTERPOLATOR),
                 new KeyValue(letter.opacityProperty(), 0f)
         ));
         timeline.play();
     }
 
  private static float getRandom(double min, double max) {
         return (float)(RANDOM.nextFloat() * (max - min) + min);
     }
  
 public static void main(String[] args){
  launch(args);
 }

}

Tuesday, August 4, 2015

Hubungan Antara Allah dengan Nomor Atom Besi

Apakah benar alam semesta ini ciptaan Tuhan adalah perdebatan yang tidak ada habisnya. Namun kita hanya bisa melakukan analisa tanpa bisa melakukan  verifikasi lebih jauh. Dalam diskusi mengenai ada atau tidaknya Tuhan ini, saya pernah menjumpai sebuah perdebatan antara muslim dan atheis. Si muslim kemudian mengajukan fakta bahwa ternyata nomor atom besi  jumlahnya sama dengan jumlah kata Allah di dalam Al-Quran. Ini kemudian dijadikan bukti bahwa tidak mungkin seorang badui di padang pasir arab mengadakan bualan semacam ini. Pasti ada the man behind the scene.

Bahasan mengenai mukjizat saintifik dalam Al-Quran pada banyak kasus tidak lebih dari sekedar kajian yang absurd. Hal yang mendasarinya adalah Al-Quran itu bukan kitab sains. Untuk membahas Al-Quran terlebih dahulu kita harus tahu sejarah dibalik penurunan Al-Quran. Kita tidak bisa secara apriori mengatakan bahwa semua “hal-hal aneh” yang terjadi selama penurunan Al-Quran adalah omong kosong (misalnya dengan menganggapnya sebagai bualan Ibnu Ishaq, Ibnu Haytam, Al-Tabari dll) lantaran adanya fakta-fakta sains yang kita temukan. Para ahli sejarah Islam sudah melakukan pengkajian secara komprehensif mengenai kejadian-kejadian yang melatarbelakangi penurunan Al-Quran (beberapa dari mereka adalah orang yang hafal seluruh isi Al-Quran). Hal yang paling maksimal yang bisa kita lakukan hanya sebatas mempelajari peninggalan mereka tersebut dan berprasangka baik terhadap mereka. 

Salah seorang muslim berkata bahwa Al-Quran memaparkan secara detail peristiwa Big Bang: bahwa bumi dan langit pada awalnya bersatu sebelum kemudian dipisahkan. Big Bang sendiri adalah salah satu model yang diajukan ilmuan untuk menjelaskan asal-usul alam semesta. Sementara model hanya bisa bekerja berdasarkan ada atau tidaknya data penunjang. Bisa jadi di kemudian hari diperoleh data-data lain (semisal bencana ultraviolet kedua) yang kemudian merontokkan atau mengkoreksi pemahaman fisis kita saat ini (termasuk model Big Bang tersebut). Sehingga alih-alih Big-Bang, dicari lah model baru dalam menjelaskan asal-usul alam semesta. Dan kemudian ayat Big-Bang itu direinterpretasi kembali dan menghasilkan makna lain dari yang kita imani saat ini.
Secara teologi kita sudah diajarkan, bahwa yang paling tahu tentang isi Al-Quran itu hanya Allah dan Nabi Muhammad. Dan berdasarkan Hadits yang diriwayatkan ke kita, tidak pernah sekalipun Al-Quran itu membahas persoalan Big Bang. Justru pada ayat yang lain, malah Al-Quran mengatakan bahwa antara langit dan bumi itu terdapat tiang-tiang penopang (mudah-mudahan ilmuan muslim masa depan bisa menjelaskan maksud ayat ini). Dan pada ayat yang lain dikatakan lagi bahwa  matahari berputar mengelilingi bumi yang kemudian diperkuat oleh penafsiran Nabi Muhammad mengenai alam semesta (bahwa matahari terbit di timur dan tenggelam di barat kemudian berjalan di bawah tanah untuk kembali lagi ke timur) yang dicatat oleh Shahih Bukhari dan diriwayatkan kepada kita. Nabi Muhammad sama sekali tidak pernah menyinggung soal Big Bang, namun anehnya  kita bisa berbicara sampai sejauh itu mengenai makna ayat-ayat tersebut.

Hal yang menjadi pertanyaan adalah kenapa angka 26 itu mesti dikaitkan dengan nomor atom besi? Nomor atom besi itu menandakan jumlah proton yang berada di dalam inti atom besi. Sementara proton (seperti halnya pada kasus Big Bang) merupakan satu dari sekian model yang diajukan para ilmuan untuk menjelaskan materi besi (dan kebetulan untuk saat ini itulah cara yang paling “benar”).  Pertanyaan selanjutnya adalah kenapa tidak atom besi sebagai sebuah kesatuan saja yang kita hubung-hubungkan dengan angka tersebut (bahwa materi besi tersusun oleh individu-individu atom besi)?

Kita tidak pernah melihat proton. Kita menyimpulkan bahwa besi disusun oleh proton lantaran ketika dilakukan sebuah eksperimen tertentu terhadap materi, terjadi sebuah fenomena tertentu yang teramati.  Fenomena ini kemudian ditafsirkan dengan membuat model yang mengatakan bahwa di dalam atom besi terdapat sebuah inti atom dan inti atom ini tersusun oleh partikel bermuatan positif bernama proton. Kita tidak pernah  melihat proton baik dengan mata fisis kita atau dengan mata batin kita. Karena ternyata mata kita juga disusun oleh proton (mana mungkin proton melihat proton…, bukannya itu sama saja dengan jeruk minum jeruk?).

Kemudian proton juga disusun oleh quark yakni dua top-quark dan satu down-quark, jadi total ada tiga. 3 x 26 = 78, lha… sudah ga sama dong dengan jumlah kata Allah di dalam surat tersebut. Kemudian besi sendiri memiliki beberapa isotop. Setahu saya ada 4 isotop besi di alam. Pertanyaanya adalah besi yang dimaksud di dalam Al-Quran ini isotop yang mana? Tolong pembaca yang paham bahasa arab bisa ga’ diterjemahkan bahwa “sebutan besi” di dalam Al-Quran itu merujuk pada isotop yang mana?

Besi itu unsur yang relatif reaktif yang sering dijumpai dalam bentuk Allotrof. Yang jadi pertanyaan besar untuk para sejarawan adalah apakah besi yang digunakan oleh masyarakat arab jaman Nabi Muhammad untuk membuat pedang, belanga dan berbagai macam keperluan  itu besi murni (dengan nama kimia Fe) atau jangan-jangan besi dengan sekian persen pengotor? Kalo dia mengandung pengotor (dan itu yang dicantumkan di dalam Al-Quran) tentu saja pekerjaan kita dalam menghubungkannya dengan angka 26 ini sangat absurd. Ketika terdapat pengotor, secara umum rumus kimianya sudah berbeda (jumlah proton penyusunnya sudah lebih dari 26).

Saya pernah melihat di internet beberapa pusaka peninggalan Nabi Muhammad, antara lain pedang beliau dan sampai saat ini masih bagus (belum berkarat). Jika demikian halnya maka itu sudah pasti bukan besi. Karena besi unsur yang reaktif. Bisa jadi besi yang dimaksud oleh Al-Quran ini adalah baja. Jika demikian tentu lain ceritanya. Karena baja  adalah gabungan antara besi yang ditambahkan karbon sekian persen untuk menambah kekuatannya. Dan  itu rumus kimianya berbeda dengan besi murni (demikian pula jumlah proton di dalamnya yang juga bukan 26). Itupun kita harus cari tahu apakah “sebutan besi” di dalam Al-Quran ini merujuk pada baja atau bukan.

Bahasa arab (juga bahasa Indonesia) sangat terbatas dalam mendeksripsikan materi yang ada di alam. Jika kita analogikan dengan air (H2O) yang tersusun oleh atom oksigen (O) dan atom hidrogen (H), apakah itu membuat kita mencocok-cocokan timbulnya kata air di dalam Al-Quran dengan jumlah nomor atom oksigen atau atau jumlah proton di dalam atom hidrogen? Bahkan sebutan kasar dalam bahasa Arab terhadap oksigen paling tinggi hanya sebatas udara (angin). Dan kita tahu udara merupakan campuran dari berbagai macam unsur selain oksigen: udara mengandung sekian persen oksigen, sekian persen hidrogen, dan sekian persen uap air.

Hal lain yang sering dikumandangkan oleh para pemikir muslim mengenai keajaiban Al-Quran adalah  jumlah kata laut (tentunya dalam bahasa arab) itu ada 32 dan kata tanah (juga dalam bahasa arab) itu ada 13. Jika dibandingkan kedua bilangan tersebut nilainya hampir sama dengan perbandingan daratan  dan lautan dewasa ini. Kata ‘tanah’ ini tentu perlu diperjelas apakah yang dimaksud adalah bumi (yang tersusun atas 7 lapis seperti yang disinggung oleh ayat yang lain) atau cuma daratan saja. Pembaca tentu lebih tahu struktur bahasa arab. Sebab jika kata tanah ini mengacu pada bumi maka rasionya sudah pasti tidak sama. Air itu hanya menyumbang sekian persen dari volume bumi. Jika yang dimaksud adalah daratan, itu pun perlu diperdebatkan lebih jauh.

Dalam geologi dikenal yang namanya gejala tektonik berupa pergeseran lempeng bumi. Akibat dari gejala ini maka  permukaan bumi mengalami perubahan sepanjang tahun. Akibatnya benua Australia dan Asia yang dulunya menyatu sekarang menjadi terpisah. Tentu rasio daratan dan lautan tidak tetap  sepanjang masa: daerah yang dulunya lautan berubah menjadi daratan demikian pula sebaliknya. Yang jadi pertanyaan adalah apakah rasio yang dimaksud oleh Al-Quran ini adalah rasionya ketika Al-Quran diturunkan, atau rasionya ketika ribuan tahun yang lalu saat sebagian besar permukaan bumi ditutupi oleh permukaan es pada zaman es. Pada zaman es tentu saja rasionya  tidak 30:70, akan tetapi ada sebagian besar daratan yang terbentuk lantaran adanya es. Dan bisa jadi ribuan tahun akan datang zaman es kembali terulang dan rasio daratan terhadap lautan menjadi lebih besar dari  30:70. Demikian pula dataran mengalami penaikan serta penurunan akibat gaya tektonik. Terbentuklah lembah, danau, gunung, palung, dll.

topografi antartika

Pada saat ini pun rasio 30:70 masih diperdebatkan. Pertama, sebagian besar daratan (‘tanah’ jika meminjam terminologi Al-Quran) benua Antartika itu berada di bawah permukaan laut. Ketebalan es di Antartika rata-rata mencapai 2 kilometer. Dengan mengingat bahwa es pada hakikatnya adalah air. Air tentu saja bukan daratan (pembaca bisa cari di google apa bahasa yang digunakan bangsa Arab pada zaman Nabi Muhammad untuk menyebut es). Jika terjadi pencairan besar-besaran es di Antartika (oleh satu dan lain faktor), maka rasio 30:70 ini bakal berkurang karena benua Antartika luasnya berkurang. Adapun benua-benua lainnya di permukaan bumi luasnya juga berkurang karena naiknya permukaan laut, sehingga rasio daratan terhadap lautan juga akan berkurang secara signifikan dari 30:70 tersebut. Akibatnya adalah “mukjizat” tersebut menjadi tidak valid lagi.

jumlah air di permukaan bumi

Ketika 5000 tahun dari sekarang di mana manusia sudah menciptakan peradaban baru. Mereka kemudian menemukan artifak-artifak kuno mengenai keajaiban Al-Quran. Bisa jadi luas daratan pada saat itu sudah jauh berkurang karena naiknya air laut. Mereka akan tahu bahwa mukjizat Al-quran itu hanya ‘cocoklogi’.


(Disadur dari berbagai sumber di internet)

Monday, August 3, 2015

Filsafat Observasi

Sebagai ilmuan tentunya kita punya preferensi dan orientasi dalam meninjau persoalan. Tapi saya percaya bahwa kebenaran itu tidaklah mutlak. Teori hanyalah hampiran terhadap realita yang sesungguhnya. Dahulu kala, sebelum manusia mendaratkan kakinya di bulan, deskripsi alam semesta digambarkan sebagai tinjauan geosentris, bahkan mungkin lebih jauh dari itu: bumi adalah dataran yang rata di mana-mana, dan matahari terbit di timur dan terbenam di barat, kemudian benda-benda langit lainnya berputar mengelilingi bumi. Dan memang benar bahwa jika kita melihat dengan mata fisis kita akan dijumpai hal seperti itu bahwa matahari terbit di timur dan tenggelam di barat. Manusia kemudian mengajukan kritik terhadap model ini. Mereka mempertanyakan lintasan planet-planet yang tidak beraturan. Waktu itu para ahli astronomi sudah mengetahui bahwa selain bintang-bintang terdapat benda langit lain yang bergantungan di atas yang pergerakannya berbeda dengan bintang-bintang secara umum. Mereka namakan ini sebagai “planet” yang secara literal diterjemahkan sebagai pengembara. Berbeda dengan bintang-bintang lainnya yang relatif tetap di tempat sepanjang tahun, ternyata planet-planet ini memiliki lintasan yang tidak regular. Dan ini yang menjadi masalah di kepala para ilmuan.

Soal asal-usul bagaimana manusia mulai mengajukan pertanyaan mengenai benda-benda langit, khususnya benda-benda yang memiliki peran langsung bagi kehidupan sehari-hari bisa dilihat pada bagaimana para petani saat ini mengatur jadwal menanam padi yang disesuaikan dengan pola musim hujan dan musim kemarau sepanjang tahun. Para petani mengamati pergantian musim tahun demi tahun dan mengamati terdapat sebuah aturan yang mendasari pergantian tersebut. Kemudian para petani mencoba mengambil keuntungan dengan adanya pola keteraturan tersebut yakni dengan mengatur waktu penanaman padi sesuai dengan waktu mulainya pergantian musim misalnya mulai menanam ketika mulai musim kemarau demi menghindari gagal panen ketika tiba musim hujan. 

Hal ini kemudian diperluas ke kasus-kasus yang lain. Bahwa selain pergantian musim hujan dan musim kemarau terdapat pula pergerakan planet-planet yang memiliki jadwal tertentu. Bahwa pergerakan ini dipercaya memiliki dampak bagi nasib umat manusia. Tahun demi tahun manusia mengajukan hasil penelitian, mengajukan berbagai macam hasil observasi (pengamatan) serta model-model yang menjelaskan data-data observasi tersebut. Untuk kasus pergerakan planet tadi memang sejak semula banyak para pemikir yang mencoba mencari tahu keteraturannya. Salah seorang pemikir terkenal yang bernama Apollonius kemudian merumuskan sebuah model yang dikenal sebagai  Epicycle dan Defferent demi menjelaskan pergerakan planet tersebut. Dalam model ini terdapat  sebuah lingkaran besar yang kosentris dengan bumi yang disebut dengan deferrent. Kemudian terdapat lingkaran kecil yang mengorbit melalui lingkaran besar ini yang disebut sebagai epicycle. Planet-planet kemudian dikatakan bergerak pada epicycle tersebut. Teori ini kemudian berhasil menjelaskan pergerakan 5 planet yang diketahui pada saat itu. Namun apa yang dilakukan oleh teori ini hanya sebatas penjelasan secara kinematis. Jika kita mencermati data-data pengamatan planet-planet di angkasa maka akan terdapat 3 variabel utama yang bisa diukur yakni posisi, kecepatan, dan percepatan. Kecepatan dan posisi merupakan variabel kinematis. Sementara percepatan sudah ada sangkut pautnya dengan gaya sehingga disebut variabel dinamika. Percepatan inilah yang sulit dijelaskan dengan konsep geocentris, khususnya dengan menggunakan model epicycle.

Model selanjutnya yang digagas oleh para saintis adalah model heliosentris. Model ini awalnya juga mendapat banyak tantangan. Salah satu hal yang dipertanyakan adalah jika memang model ini benar, maka seharusnya  dijumpai parallax bintang oleh pengamat yang berada di bumi seiring dengan perubahan posisi pengamatan pengamat di bumi. Namun karena tidak adanya parallax bintang yang teramati, maka dapat disimpulkan bahwa bumi stasioner atau tidak mengalami pergerakan. Pada akhirnya di abad ke-18 ilmuan dapat mengukur parallax bintang kendatipun sangat kecil yang konsekwensinya adalah jarak antara bumi dan bintang-bintang tersebut sangatlah jauh. Sehingga ini makin menguatkan konsep heliosentris. Aplikasi dari konsep heliosentris ini kemudian yang digunakan oleh para ilmuan dalam mendaratkan pesawat ruang angkasa di Mars dan di bulan yang sama sekali sulit dilakukan jika menggunakan tinjauan geosentris. 

Konsep heliosentris kemudian disempurnakan oleh Johannes Kepler  dengan mengganti lintasan planet yang semula diasumsikan berbentuk lingkaran menjadi berbentuk elips di mana matahari berada pada salah satu titik fokus dari elips tersebut. Salah satu Hukum Kepler menyatakan bahwa ketika planet bergerak maka luas area yang disapu oleh garis yang menghubungkan antara planet dengan matahari sama besarnya untuk kurun waktu yang sama. Oleh Newton kemudian dilakukan penjelasan bahwa ini disebabkan oleh gaya gravitasi yang diberikan oleh matahari terhadap planet-planet tersebut. Dan pergerakan planet ini merupakan konsekwensi logis dari gaya gravitasi.

Sunday, May 17, 2015

Menggunakan komponen java swing dari MATLAB

Berikut ini saya contohkan script tentang bagaimana memanggil komponen java swing dari MATLAB:
clc; 
frame = javax.swing.JFrame; 
frame.setSize(300,300);
frame.setTitle('Hello'); 
frame.setLocationRelativeTo([]); 
frame.setLayout([]); 

button1 = javax.swing.JButton('TEST'); 
button1.setBounds(20,20, 120,30 ); 

label = javax.swing.JLabel('');  
label.setBounds(20,60, 120,30); 

set(button1, 'MouseClickedCallback' , ... 
    @(h,e)(set(label, 'text', ['kalian luar biasa...! ',...
    num2str(randi(11,1))]))); 

frame.add(label); 
frame.add(button1); 
frame.show; 
Yang hasil eksekusinya adalah sebagai berikut:

Saturday, March 28, 2015

Mengatur Area Blur Pada Image Dengan Mouse Scroll di MATLAB

Dalam tutorial kali saya akan memberikan contoh bagaimana mengatur area blur (region of interest yang akan di-blur) dari gambar dengan menggunakan mouse scroll pada MATLAB. Source codenya saya berikan langsung yakni
% test window scroll function untuk memblur gambar. Gunakan mouse scroll
% untuk memperluas atau mempersempit lokasi blur
function testWindowScroll 
clear all; 
clc; 
f = figure('WindowScrollWheelFcn',@sliderHandle,'menubar', 'none' ); 
ax = axes('parent', f, 'units', 'pix' ); 
im = (imread('gambar 1/lion-test.jpg')); % disesuaikan 

imshow(im,'parent', ax); 

sizeImage = size(im);
w = sizeImage(2); 
h = sizeImage(1); 
halfW = double(w)/2; 
halfH = double(h)/2;
maxD = min(w,h)/2; 

initD = 100; 

blurImage(initD); 

    function sliderHandle(src, event)
        m = get(0, 'PointerLocation'); 
        xMouse = m(1); 
        yMouse = m(2); 
        
        posFig = get(f, 'position'); 
        xFig = posFig(1); 
        yFig = posFig(2); 
        widthFig = posFig(3); 
        heightFig = posFig(4); 
        
        if (xMouse > xFig ) && (yMouse > yFig ) && ... 
                (xMouse < xFig + widthFig ) && ... 
                (yMouse < yFig + heightFig )
            if event.VerticalScrollCount < 0  % up 
                initD = initD + 3; 
            elseif event.VerticalScrollCount > 0 % down 
                if initD - 3 > 0 
                   initD = initD - 3;
                end
            end     
            blurImage(initD);
        end
    end

    function blurImage(d)
        if d < maxD
            [xx,yy] = ndgrid(( 1:h )-halfH , ( 1:w ) - halfW ) ; 
            mask = uint8( ( xx.^2 + yy.^2 ) > d^2);
            G = fspecial('disk', 10); 
            cropped = uint8(zeros(sizeImage)); 
            cropped(:,:,1) = roifilt2(G ,im(:,:,1) , mask ); 
            cropped(:,:,2) = roifilt2(G ,im(:,:,2) , mask ); 
            cropped(:,:,3) = roifilt2(G ,im(:,:,3) , mask ); 
            imshow( cropped );  
            drawnow; 
        end
    end
end 
Di mana video implementasinya di komputer saya adalah sebagai berikut

Friday, March 20, 2015

Cara Sorting Cell di MATLAB

Berikut ini adalah contoh bagaimana men-sorting cell di MATLAB:
clear all; 
clc; 
% test sorting dari cell
M = cell(4,2); 
M{1,1} = 'mawar'; 
M{1,2} = 23;
M{2,1} = 'Anggrek' ;
M{2,2} = 11; 
M{3,1} = 'Durian'; 
M{3,2} = 45; 
M{4,1} = 'Benalu'; 
M{4,2} = 222;

% sorting berdasarkan jarak
N = sortrows(M,2);
disp(M); 
disp(N);


% output 
%     'mawar'      [ 23]
%     'Anggrek'    [ 11]
%     'Durian'     [ 45]
%     'Benalu'     [222]
% 
%     'Anggrek'    [ 11]
%     'mawar'      [ 23]
%     'Durian'     [ 45]
%     'Benalu'     [222]

Monday, February 23, 2015

Memahami Epicycle

Dahulu kala, sekitar 1000 tahun sebelum masehi orang-orang masih berpatokan pada konsep geosentris yakni memposisikan bumi sebagai pusat alam semesta. Data-data pergerakan planet pada waktu itu (yang diamati melalui teleskop) sudah banyak tersedia. Ini kemudian coba dimodelkan untuk mencari tahu bagaimana lintasan planet-planet relatif terhadap bumi sebagai pusat tata surya (alam semesta). Namun ternyata data-data tersebut jika ditafsirkan dengan konsep geosentris, akan terlihat bahwa gerakan planet-planet yang diketahui pada saat itu, tampak sangat tidak beraturan. Dan ini sangat bertentangan dengan teologi bahwa alam semesta diciptakan oleh Tuhan yang menyukai keteraturan.

Datang lah seorang Ptolemeus yang memberikan sebuah penjelasan bahwa lintasan planet-planet tersebut dapat dipandang sebagai lintasan titik dalam dalam geometri epicycle. Ini mampu menjelaskan keteraturannya yang diasumsikan berdasarkan kehendak Tuhan. Ptolemeus dan ilmuan-ilmuan sesudahnya kemudian berasumsi bahwa Tuhan sangat menyukai bentuk lingkaran.

Pada tulisan selanjutnya saya akan membuktikan bahwa dengan epicycle, kita bukan hanya bisa men-track lintasan planet dengan konsep geosentris, akan tetapi lintasan apa saja yang berbentuk kurva tertutup. Ini tidak lain merupakan implikasi dari analisis fourier yang secara kasar menegaskan bahwa semua fungsi perodik bisa dinyatakan sebagai penjumlahan dari fungsi-fungsi sinusoidal

Saya punya project di github tentang bagaimana epicycle dapat menghasilkan sebuah lintasan yang tidak teratur namun tetap berbentuk kurva tertutup.

Tuesday, December 23, 2014

Plot Fungsi Gaussian Dengan MATLAB

Fungsi Gaussian didefenisikan oleh persamaan
\begin{equation} f(x) = a \exp \left ( - \frac{(x - b )^2 }{ 2 \, c^2 } \right ) \label{pers1} \end{equation} Dengan $a$, $b$, dan $c$ konstanta real sembarang. Untuk memahami karakteristik persamaan \ref{pers1} di atas, Anda dapat mencoba potongan script berikut
clear all; 
clc; 
% test sorting dari cell
M = cell(4,2); 
M{1,1} = 'mawar'; 
M{1,2} = 23;
M{2,1} = 'Anggrek' ;
M{2,2} = 11; 
M{3,1} = 'Durian'; 
M{3,2} = 45; 
M{4,1} = 'Benalu'; 
M{4,2} = 222;

% sorting berdasarkan jarak
N = sortrows(M,2);
disp(M); 
disp(N);


% output 
%     'mawar'      [ 23]
%     'Anggrek'    [ 11]
%     'Durian'     [ 45]
%     'Benalu'     [222]
% 
%     'Anggrek'    [ 11]
%     'mawar'      [ 23]
%     'Durian'     [ 45]
%     'Benalu'     [222]

Friday, December 19, 2014

Perkalian matriks secara parallel

Pada posting ini, saya akan menyajikan kelanjutan posting saya sebelumnya, yakni posting mengenai perkalian matriks secara rekursi.  Namun dalam posting ini saya akan menekankan pada aspek manfaatnya.

Orang-orang bisa berkata buat apa kita melakukan rekursi jika hasilnya sama saja? Jawabnya ada di posting kali ini.

Dalam rilis terbaru  bahasa Java yakni Java 7 telah diperkenalkan konsep paralellisme dengan cara yang lebih modern dibandingkan sebelumnya. Yakni dengan memasukkan beberapa class baru ke dalam Java Standard Library yang khusus untuk menangani keperluan parallelisme. Dua class yang dimaksud adalah RecursiveAction dan RecursiveTask. Ada sebuah posting menarik dari oracle yang membahas mengenai masalah ini.

Pada kesempatan kali ini saya akan mengekspose fitur yang disajikan class yang dimaksud untuk keperluan meningkatkan efisiensi dalam perkalian matriks. Mekanismenya sudah dijelaskan pada posting saya sebelumnya (tentang perkalian matriks secara rekursi). Hanya dalam posting ini, matriks C yang sudah dipecah ke dalam sub-sub-sub… matriks C, elemennya di-isi secara parallel. Akibatnya adalah waktu eksekusi bisa berkurang hingga setengahnya. Jadi ketika secara normal dia membutuhkan waktu 10 detik, maka dengan parallelisme dia hanya membutuhkan waktu 5 detik. Saya sudah memposting di github project saya tersebut, dan Anda bisa mencobanya di rumah. Mudah-mudahan hasilnya tidak beda  jauh dari apa yang saya peroleh.

Dalam hasil percobaan saya, dilakukan perkalian dua buah matriks yakni matriks A dengan ukuran (1000,600) dan matriks B dengan ukuran (600,9000) di mana waktu eksekusi dengan cara tradisional membutuhkan waktu 143 detik, sementara waktu eksekusi dengan cara parallel membutuhkan waktu 73 detik.

Wednesday, December 17, 2014

Perkalian Matriks Secara Rekursi

Dalam kesempatan kali ini saya akan memberikan sedikit pencerahan tentang bagaimana mengalikan matriks secara rekursi.

Di dalam dunia pemrograman, rekursi didefenisikan sebagai pemecahan masalah dengan cara membaginya ke dalam sub bagian yang lebih kecil. Hal ini ditandai dengan adanya panggilan terhadap fungsi/method dari dalam method/fungsi itu sendiri.

Kali ini saya akan memberikan contoh bagaimana operasi perkalian matriks bisa dilakukan secara rekursi. Artinya ketimbang melakukan iterasi satu per satu terhadap semua elemen matriks untuk memperoleh hasil akhir. Maka dengan rekursi, kita melakukan perkalian secara simultan terhadap kelompok-kelompok elemen dari matriks tersebut.

Metodenya adalah dengan membagi matriks ke dalam 4 kuadran,  yang masing-masing bagian akan dibagi lagi menjadi 4 kuadran secara berkelanjutan, hingga dijumpai base case. Pada base case ini baru kemudian dilakukan perhitungan secara langsung. Base-case diperlukan dalam rekursi, karena jika tidak ada base-case, maka akan terjadi pemanggilan berulang-ulang tanpa henti yang berakibat alokasi berlebihan terhadap memori stack pada komputer. Dan ujung-ujungnya terjadi stack-overflow.

Prinsip kerjanya adalah, ketika matriks A dengan dimensi (m,n) dengan m menyatakan jumlah baris dan n jumlah kolom dikalikan dengan matriks B dengan dimensi (o,p), maka matriks hasil akan berdimensi (m,p). Jadi yang kita lakukan adalah menerapkan rekursi dalam pengisian elemen dari matriks hasil tadi (katakanlah matriks C).  Perhatikan potongan script berikut

	
public void multiply(int barisA, int kolomB) {
int sum = 0;
for (int k = 0; k < dimensiTengah; k++) {
sum += matriksA[barisA][k] * matriksB[k][kolomB];
}
matriksC[barisA][kolomB] = sum;
}
Dalam potongan script di atas, kita melakukan pengisian elemen ke (i,j) pada matriks C dengan mengalikan elemen pada baris ke-i matriks A dengan kolom ke-j matriks B lantas menjumlahkannya. Di sini kuncinya! Jadi dengan melakukan rekursi terhadap baris dan kolom matriks C  maka kita tidak perlu lagi pusing memikirkan bagaimana mengkondisikan elemen matriks B dan elemen dari matriks A untuk keperluan perkalian matriks secara rekursi. Yang perlu kita pikirkan hanya proses pengisian elemen dari matriks C tadi.

Kita akan melakukan proses pengisian tersebut dengan membagi matriks C ke dalam 4 kuadran secara rekursi sampai diperoleh base case. Base case dijumpai ketika jumlah baris serta jumlah kolom dari sub matriks C---matriks yang diperoleh dari pemecahan matriks C ke dalam 4 kuadran tadi (walaupun hakikatnya dalam memori hanya matriks C juga)---telah melampaui ambang tertentu. Perhatikan potongan script berikut.

public void compute() {

int limit = 10;

int limitKolom = (int) (Math.floor( ((awalKolom - akhirKolom) / 2)));

int limitBaris = (int) (Math.floor( ((akhirBaris - awalBaris) / 2)));

int halfBaris = awalBaris + limitBaris;

int halfKolom = awalKolom + limitKolom;


if (limitKolom <= limit && limitBaris <= limit) {

computeDirectly(awalBaris, akhirBaris, awalKolom, akhirKolom);

return;

} else if (limitBaris <= limit && limitKolom > limit) { // split over column

RecursiveMatrixMultiplication p2 = new RecursiveMatrixMultiplication(matriksA, matriksB,
matriksC, dimensiTengah, awalBaris, akhirBaris, awalKolom,
halfKolom);

RecursiveMatrixMultiplication p4 = new RecursiveMatrixMultiplication(matriksA, matriksB,
matriksC, dimensiTengah, awalBaris, akhirBaris, halfKolom,
akhirKolom);

invokeAll(p2, p4);

} else if (limitKolom <= limit && limitBaris > limit) { // split over
// row

RecursiveMatrixMultiplication p1 = new RecursiveMatrixMultiplication(
matriksA, matriksB,matriksC,
dimensiTengah,
awalBaris, halfBaris,
awalKolom, akhirKolom);

RecursiveMatrixMultiplication p3 = new RecursiveMatrixMultiplication(
matriksA, matriksB, matriksC,
dimensiTengah,
halfBaris, akhirBaris,
awalKolom, akhirKolom);

invokeAll(p1, p3);

} else if (limitKolom > limit && limitBaris > limit) { // split to 4 quadran

RecursiveMatrixMultiplication p1 = new RecursiveMatrixMultiplication(
matriksA, matriksB, matriksC, dimensiTengah,
awalBaris, halfBaris,
awalKolom, halfKolom); // kuadran 1

RecursiveMatrixMultiplication p2 = new RecursiveMatrixMultiplication(
matriksA, matriksB,matriksC, dimensiTengah,
halfBaris, akhirBaris,
awalKolom, halfKolom); // kuadran 2

RecursiveMatrixMultiplication p3 = new RecursiveMatrixMultiplication(
matriksA, matriksB, matriksC , dimensiTengah,
awalBaris, halfBaris,
halfKolom, akhirKolom); // kuadran 3

RecursiveMatrixMultiplication p4 = new RecursiveMatrixMultiplication(
matriksA, matriksB, matriksC, dimensiTengah,
halfBaris, akhirBaris,
halfKolom, akhirKolom); // kuadran 4

invokeAll(p1, p2, p3, p4);

}

}

Dalam potongan di atas, ketika jumlah baris dari sub-matriks C dan jumlah kolomnya masih lebih besar dari ambang, maka bagi lagi secara rekursi menjadi sub-sub matriks berikutnya (dalam 4 kuadran). Ketika jumlah baris masih lebih besar dari ambang, bagi sub-matriks C ke dalam dua sub-matriks berikutnya dalam arah horizontal  (bagi baris-barisnya ke dalam dua bagian). Sementara jika jumlah kolomnya masih lebih besar dari ambang, maka bagi sub-matriks C dalam arah vertikal (bagi kolom-kolomnya menjadi dua bagian).

Ketika dijumpai base-case, yakni ketika jumlah kolom dan jumlah baris dari sub-sub-sub-sub… matrik C lebih kecil dari nilai ambang, maka lakukan perkalian elemen-elemen matriks A dan matriks B untuk mengisi elemen-elemen dari sub-sub-sub… matriks C tersebut.

Secara keseluruhan kode yang digunakan adalah sebagai berikut (di dalamnya terdapat juga method untuk mengecek kevalidan operasi yakni dengan membandingkannya dengan perkalian secara konvensional, tanpa rekursi).  

package algo.test.multiply;

import java.util.Random;

public class RecursiveMatrixMultiplication {

int[][] matriksA;
int[][] matriksB;
int[][] matriksC;

int awalBaris;
int awalKolom;
int akhirBaris;
int akhirKolom;

int dimensiTengah;

public RecursiveMatrixMultiplication(int[][] matriksA, int[][] matriksB,
int[][] matriksC, int dimensiTengah, int awalBaris, int akhirBaris,
int awalKolom, int akhirKolom) {

this.matriksA = matriksA;
this.matriksB = matriksB;
this.matriksC = matriksC;

this.awalBaris = awalBaris;
this.awalKolom = awalKolom;
this.akhirBaris = akhirBaris;
this.akhirKolom = akhirKolom;

this.dimensiTengah = dimensiTengah;
}

public void multiply(int barisA, int kolomB) {
int sum = 0;
for (int k = 0; k < dimensiTengah; k++) {
sum += matriksA[barisA][k] * matriksB[k][kolomB];
}
matriksC[barisA][kolomB] = sum;
}


private void computeDirectly(int awalBaris, int akhirBaris, int awalKolom,
int akhirKolom) {
for (int i = awalBaris; i < akhirBaris; i++) {
for (int j = awalKolom; j < akhirKolom; j++) {
multiply(i, j);
}
}
}


public void invokeAll(RecursiveMatrixMultiplication...matrixMultiplications ){
for(RecursiveMatrixMultiplication m: matrixMultiplications){
m.compute();
}
}

public void invoke(){
invokeAll(this);
}

public void compute() {

int limit = 10;

int limitKolom = (int) (Math.floor( ((awalKolom - akhirKolom) / 2)));

int limitBaris = (int) (Math.floor( ((akhirBaris - awalBaris) / 2)));

int halfBaris = awalBaris + limitBaris;

int halfKolom = awalKolom + limitKolom;


if (limitKolom <= limit && limitBaris <= limit) {

computeDirectly(awalBaris, akhirBaris, awalKolom, akhirKolom);

return;

} else if (limitBaris <= limit && limitKolom > limit) { // split over column

RecursiveMatrixMultiplication p2 = new RecursiveMatrixMultiplication(matriksA, matriksB,
matriksC, dimensiTengah, awalBaris, akhirBaris, awalKolom,
halfKolom);

RecursiveMatrixMultiplication p4 = new RecursiveMatrixMultiplication(matriksA, matriksB,
matriksC, dimensiTengah, awalBaris, akhirBaris, halfKolom,
akhirKolom);

invokeAll(p2, p4);

} else if (limitKolom <= limit && limitBaris > limit) { // split over
// row

RecursiveMatrixMultiplication p1 = new RecursiveMatrixMultiplication(
matriksA, matriksB,matriksC,
dimensiTengah,
awalBaris, halfBaris,
awalKolom, akhirKolom);

RecursiveMatrixMultiplication p3 = new RecursiveMatrixMultiplication(
matriksA, matriksB, matriksC,
dimensiTengah,
halfBaris, akhirBaris,
awalKolom, akhirKolom);

invokeAll(p1, p3);

} else if (limitKolom > limit && limitBaris > limit) { // split to 4 quadran

RecursiveMatrixMultiplication p1 = new RecursiveMatrixMultiplication(
matriksA, matriksB, matriksC, dimensiTengah,
awalBaris, halfBaris,
awalKolom, halfKolom); // kuadran 1

RecursiveMatrixMultiplication p2 = new RecursiveMatrixMultiplication(
matriksA, matriksB,matriksC, dimensiTengah,
halfBaris, akhirBaris,
awalKolom, halfKolom); // kuadran 2

RecursiveMatrixMultiplication p3 = new RecursiveMatrixMultiplication(
matriksA, matriksB, matriksC , dimensiTengah,
awalBaris, halfBaris,
halfKolom, akhirKolom); // kuadran 3

RecursiveMatrixMultiplication p4 = new RecursiveMatrixMultiplication(
matriksA, matriksB, matriksC, dimensiTengah,
halfBaris, akhirBaris,
halfKolom, akhirKolom); // kuadran 4

invokeAll(p1, p2, p3, p4);

}

}


/*
* bandingkan matriksA dan matriksB..
* jika semua elemennya sama, maka kembalikan matriksC yang isinya semua 1...
* jika ada elemen yang beda isi elemen matriksC dengan 0
*/
public static int [][] compareMatriks(int [][] matriksA, int[][] matriksB){
int C[][] = new int [matriksA.length][matriksA[0].length];
for( int i=0; i < matriksA.length ;i++){
for(int j=0; j < matriksA[0].length ;j++){
if(matriksA[i][j] == matriksB[i][j]){
C[i][j] = 1;
}else{
C[i][j] = 0;
}
}
}
return C;
}


/*
* sebagai pembanding untuk mengetahui operasi berjalan dengan benar..
* yakni lakukan perkalian secara Langsung.. tanpa rekursive...
*/
public static int[][] multiplyDirectly(int [][] matriksA, int[][] matriksB){
int result[][] = new int[matriksA.length][matriksB[0].length];
for(int i= 0; i< matriksA.length ;i++){
for(int j=0; j< matriksB[0].length ;j++){
int sum = 0;
for( int k = 0 ; k < matriksB.length ;k ++){
sum += matriksA[i][k] * matriksB[k][j];
}
result[i][j] = sum;
}
}
return result;
}

/*
* generate random matriks
*/
public static int [][] generateMatriks(int baris, int kolom){
int matriks[][] = new int[baris][kolom];
Random rn = new Random();
for(int i=0; i < matriks.length ; i++){
for( int j=0; j < matriks[0].length ;j++){
matriks[i][j] = rn.nextInt(100);
}
}
return matriks ;
}


/*
* pretty print matrix
*/
public static void printMatriks(int [][] matriks) {
for (int i = 0; i < matriks.length; i++) {
for (int j = 0; j < matriks[0].length; j++) {
System.out.print(matriks[i][j] + "|");
}
System.out.print("\n");
}
System.out.print("\n");
}


public int[][] getResult() {
return matriksC;
}


public static void main(String[] args){


int[][] matriksA = generateMatriks(300, 200);
int[][] matriksB = generateMatriks(200, 500);

long now = System.nanoTime();

int[][] matriksResultA = multiplyDirectly(matriksA, matriksB);

now = (System.nanoTime() - now) / 1000000;

long now1 = System.nanoTime();

int[][] matriksC = new int[matriksA.length][matriksB[0].length];

RecursiveMatrixMultiplication parallel = new RecursiveMatrixMultiplication(matriksA, matriksB, matriksC,
matriksB.length, 0 , matriksC.length, 0, matriksC[0].length);

parallel.invoke();

int[][] matriksResultB = parallel.getResult();

now1 = (System.nanoTime() - now1) / 1000000;

int[][] hasilCompare = compareMatriks(matriksResultA, matriksResultB);

printMatriks(hasilCompare);

System.out.println(now);
System.out.println(now1);
System.out.println("FINISH");

}


}