Blog do projektu Open Source JavaHotel

środa, 28 sierpnia 2013

Clojure and polynomials

Introduction
I started reading through Clojure tutorial and found very interesting implementation of calculating polynomial and its first derivative. So I decided to stretch my math muscle and perform more polynomial arithmetic in Clojure basing on this article.
I'm assuming all the time that polynomial in Clojure is a list of coefficients from left to right (like in the written form). So list [2 8 9]  means 2x² + 8x + 9, [7 0 1 7] means: 7x³ + x + 7
Addition
Almost nothing more than (map + ...) function. The only problem is to expand shorter list (lower degree polynomial). Also improvement should be added to reduce the leading zeros from the result. Example:
(2x² + 8x + 9) + (-2x² + 2x + 4) = 0x² + 10x + 13

(defn addpol
  [pol1 pol2]
  ; degree of the sum polynomial 
  (let [nsize (max (count pol1) (count pol2) ) ]
  ; expand polynomial to the new degree by adding 0 coefficient at the frot
    (defn expandpol 
        [pol] 
            (concat ( repeat (max 0 (- nsize (count pol))) 0 ) pol )
    )
  )
  ; having both polynomials at the same degree just sum them
  (map + (expandpol pol1) (expandpol pol2))
)
Subtraction
Just use the previous function and negate the subtrahend.
(defn subtractpol
  [minuend subtrahend]
  ; negate subtrahend and run summing
  (addpol minuend ( map #(- 0 %) subtrahend))
)
Product
Multiply every coefficient of the first polynomial by every coefficient of the second polynomial. Recursion is used to iterate but this algorithm is a good candidate for loop->recur for better performance.

(defn mulpol
  [pol1 pol2]
  ( let
    ; level of the product
      [newlevel (- (+ (count pol1) (count pol2)) 1)]  
    ; multiply polynomial by digit and add zeros at the frond and end keeping it at the degree necessary
    (defn muldigit 
       [beg coeff end]
       (concat (repeat beg 0) (map #(* % coeff) pol2) (repeat end 0))
    )
    ; recursive as replacement for iteration
    (defn muladd
       ; 'beg' number of left zeros
       ; 'currentsum' list of coefficient multiplications peformed so far
       ; 'restpol1' list of coefficients not used yet
       ; 'end' number of right zeros
       [beg currentsum restpol1 end]
       (condp = restpol1
       ; end of recursion
       [] currentsum
       ; multiply and move to the next digit
       (
         map
            +
            currentsum
            (muladd 
               (+ beg 1)
               (muldigit beg (first restpol1) end)
               (rest restpol1)
               (- end 1)
            )
       )
       )
     )
  ; start of the recursion
  ( muladd 0 (repeat newlevel 0) pol1 (- newlevel (count pol2)))
  )
)
Division
Is more complicated because two results are expected: quotient and remainder. So to bring the result a map is used. Polynomial long division is implemented as easier. This function should be expanded to exclude division by zero (empty divisor) and reduce leading zeros from divisor. Example: (0 4 5)

; returns a map with two keys :quotient and :remainder
(defn divpol 
   [divident divisor]
   ; perform (lead(r)/lead(divisor)) * divisor
   (defn multerm
     [r resdiv]
       (concat (map #(* resdiv %) divisor) (repeat (- (count r) (count divisor)) 0))
   )
   ; recursive
   (defn div 
     [mapd]
   ( let [ q (get mapd :quotient)
           r (get mapd :remainder) 
           dv (/ (first r) (first divisor)) 
         ]
   ; end of recursion, pass down the result
   (if (or (< (count r) (count divisor)) (empty? r))
       mapd
   ; pull down the next digit from divident
       (div ( hash-map 
              :quotient (conj q dv)
              :remainder (rest (map - r (multerm r dv)))
            )
       )
   )
   )
   )   
   ; beginning of the recursion
   (div ( hash-map :quotient [], :remainder divident))
)   

niedziela, 18 sierpnia 2013

MVP Jython framework, html panel and javascript code

Introduction
The dialog is displayed using default layout. The default layout is convenient at the beginning but later probably something more useful and better looking is necessary. So it is possible to replace default layout by means of GWT HTMLPanel widget. Just add to the dialog definition file containing dialog layout in shape of html page and new display is visible. Also custom Javascript code can be added to the page.
TabPanel is very useful way of displaying a lot of data on the screen without scrolls. TabPanel can be built by combining html, css and javascript code but GWT contains TabPanel widget.
HTMLPanel and JavaScript custom code

Sample application is available here (click at "Dialog HTML panel"). The html, css and JavaScript code was downloaded from this page. It does not make a lot of sense here, it is only a presentation how default layout can be enriched with html, css and custom Javascript code. More detailed description is available here.
Adding HTMLPanel definition impacts only presentation part. It does not involve any change in backing Jython code.
TabPanel

Sample application is available here (click at "Dialog tab panel"). The usage of the TabPanel is limited currently. For instance it is not possible to disperse buttons between different tab pages. More detailed description is available here.  
Problems
  • Current implementation of HTMLPanel does not allow to use custom (internationalized) labels. It will be added later.
  • Current implementation of TabPanel is limited. More flexible approach will be added later.

czwartek, 1 sierpnia 2013

MVP Jython framework and edit grid

Introduction
I added a new widget to my MVP framework. It is an "edit grid" which allows modification data in the list directly (like in this GWT showcase) but allowing adding and removing rows dynamically.

This widget can be used when a number of fields is relatively small (containable in one line) and line editing is more natural then standard CRUD editing. Google App Engine live demo version is available here. Detailed description here, also source code and Selenium unit tests.
Problem
The main problem I found was to detect "the end of edit single line". There is no any direct "finish" button. This action is necessary to perform data validation and store data in persistence layer (assuming that one line reflects one record). The only solution I found was to discover the end of line editing after moving to the another line. In this case editing of the next line is suspended for moment and actions related to the last line are executed. If data validation fails then user is forced to return to the previous line and fix the data.
From that stems another problem. When user wants to finish editing he simply clicks "Accept" (or any other) button without moving to the next line. So it was necessary also to provide a way to declare which buttons requires validation of the last line.
 There are two ways of making data persisted. One is to persist data after any action relating to data change (after single column or whole line) or store all lines at the end of editing (after pressing "Accept" button or any other). In this case it is necessary to transport all data from the client to the server side. In order to avoid unnecessary traffic there is a way to specify which buttons trigger data transportation and which buttons do not. When data persisting is done at the end of editing there is a risk of losing all data just entered in case of any failure.
Next steps
I plan to use this widget in the JavaHotel application is several cases. The first case will be manually changing list price for reservation and bypass prices provided from regular price list.