Category : Programming

HQ9+, H9+, KL esoterical languages and the beer song

April 4th, 2011 by Ivan Lakhturov | 0 Category: Programming | Tags: |

Let's first sing a beer song (in R6RS Scheme):

  1. #!r6rs
  2. (library (sing-beer-song)
  3.          (export sing-beer-song)
  4.          (import (rnrs))
  5.  
  6.          (define (sing-beer-song n)
  7.            (define (n-bottles i capital?)
  8.              (string-append
  9.               (cond
  10.                 ((eqv? i -1) (number->string 99))
  11.                 ((and (eqv? i 0) capital?) "No more")
  12.                 ((eqv? i 0) "no more")
  13.                 (else (number->string i)))
  14.               " bottle" (if (eqv? i 1) "" "s")
  15.               " of beer"))
  16.            (define (where?) " on the wall")
  17.            (define (what-to-do? n)
  18.              (if (> n 0) "Take one down and pass it around, "
  19.                  "Go to the store and buy some more, "))
  20.            (string-append
  21.             "\n" (n-bottles n #t) (where?) ", " (n-bottles n #f) ".\n"
  22.             (what-to-do? n) (n-bottles (- n 1) #f) (where?) ".\n"
  23.             (if (> n 0) (sing-beer-song (- n 1)) ""))))

Then let's make an extra library:

  1. #!r6rs
  2. (library (language-utilities)
  3.          (export glue)
  4.          (import (rnrs))
  5.  
  6.          (define (glue los) (fold-left string-append "" los)))

... and we are ready to write yet-another HQ9+ interpreter:

  1. #!r6rs
  2. (import (rnrs) (sing-beer-song) (language-utilities))
  3.  
  4. ; HQ9+ interpreter v0.1 (Ivan Lakhturov)
  5. ; http://esolangs.org/wiki/HQ9
  6.  
  7. (define i 0)
  8.  
  9. (define (run-program s)
  10.   (define (run-command c)
  11.     (cond
  12.       ((eqv? c #\H) "Hello, World!")
  13.       ((eqv? c #\Q) s)
  14.       ((eqv? c #\9) (sing-beer-song 99))
  15.       ((eqv? c #\+) (set! i (+ i 1)) "") ; (number->string i))
  16.       (else (string c))))
  17.   (glue (map run-command (string->list s))))  
  18.  
  19. (display (run-program "HQ9+"))

HQ9+ is a joke language, featuring "Hello world" command, quine command, beer-song command and a counter increment (counter cannot be accessed or printed out). Quine implementation here is the classical "quine-cheating", where a program has access to its source. To make the quine more 'honest' somebody designed H9+. This is the same as HQ9+, but without "Q" command, and additionally, all characters on input are ignored, except for H, 9 and +. Then, obviously, "Hello, World!" program will be a quine. Let's implement H9+:

  1. #!r6rs
  2. (import (rnrs) (sing-beer-song) (language-utilities))
  3.  
  4. ; H9+ interpreter v0.1 (Ivan Lakhturov)
  5. ; http://esolangs.org/wiki/H9
  6.  
  7. (define i 0)
  8.  
  9. (define (run-program s)
  10.   (define (run-command c)
  11.     (cond
  12.       ((eqv? c #\H) "Hello, World!")
  13.       ((eqv? c #\9) (sing-beer-song 99))
  14.       ((eqv? c #\+) (set! i (+ i 1)) "") ; (number->string i))
  15.       (else "")))
  16.   (glue (map run-command (string->list s))))  
  17.  
  18. (display (run-program "Hello, World!"))

And let's implement also a variation of this theme, the esoterical language KL:

  1. #!r6rs
  2. (import (rnrs) (language-utilities))
  3.  
  4. ; KL interpreter v0.1 (Ivan Lakhturov)
  5. ; http://ivanguide.ru/kl/
  6.  
  7. (define (run-program s)
  8.   (define (run-command c)
  9.     (cond
  10.       ((eqv? c #\+) "Привет, мир!")
  11.       ((eqv? c #\-) s)
  12.       ((eqv? c #\*)
  13. "Я узнал, что у меня
  14. Есть огpомная семья –
  15. И тpопинка, и лесок,
  16. В поле каждый колосок!
  17.  
  18. Речка, небо голубое –
  19. Это все мое, pодное!
  20. Это Родина моя!
  21. Всех люблю на свете я!")
  22.       ((eqv? c #\/) "\n")
  23.       (else (string c))))
  24.   (glue (map run-command (string->list s))))  
  25.  
  26. (display (run-program "+/-/*/extras"))

The semantics is as following: + is printing "Hello, world!" in Russian, - is printing a program's source, / is making a newline, and * print outs a poem from Russian movie "Brother".

To complete the picture, we can mention other close related to HQ9+ joke languages: HQ9++, CHIQRSX9, HQ9+B, HQ9+2D. HQ9++ is 'an object-oriented extension of HQ9+'; not interesting. CHIQRSX9+ adds eval, ROT-13 and sorting of input lines. ROT-13 (Caesar cipher) is a nice exercise to implement, but let's leave it for later. HQ9+B adds Brainfuck: this is definitely a thing to implement, but I will deal with Brainfuck later. HQ9+2D is not properly specified (even for a joke language), but commands it adds remind me 2D Turing-machine, so called Langton's ant. I want to implement and play with different Turing-machines, but later.

Later I will also look through the list of joke languages. For example, the first there is a 'language' 99, which just prints out '99 bottles of beer' song. Anyways, I hope, there could be something exciting in the list.

Aerodynamic calibration rig

October 6th, 2010 by Ivan Lakhturov | 0 Category: Programming | Tags:

More than five years ago I worked for "DX-Complexes" and "Spectromed-UA". Here is a video about one of the projects I accomplished there. This is the aerodynamic calibration rig for metrological testing of spirographs. (What is a spirograph? See spirometry topic at Wikipedia).

http://www.youtube.com/watch?v=y4KBf_SQJhk

There is no sound in this video, cause we wanted to make a promo-video out of this, and some voiceover was supposed to be done later. But the device was too specialized, so we decided not to. So, let it be an advertisement for myself.

The schematics is in the illustration:

I operate the control program, written in C#, which communicates by COM-port with the embedded program in C. Both are written by me. Then this embedded program drives the device you see on video. It consists of electronics, the engine, worm gear and a piston going forwards and backwards in a plexiglass cylinder. The air flow generated by the device is registered with a spyrograph, connected via USB-port to another PC, where a third-party spirometry program is installed (visible in the second part of video).

Naturally, to verify the accuracy of a spiro-device, the calibration rig has to be in sctrict accuracy limits itself. It wasn't so trivial to achieve those specs. I remember one of the problems with overjumps: when you turn off the power of an engine, the piston doesn't stop momentarily due to inertia and slips further. What's the solution? To apply maximal reverse force via the engine as soon as the piston is supposed to stop. A period of time when we apply that reverse force depends on a few hard-to-estimate factors, so it was easier to fit this empirically.

This device can be considered as a very simple 'robot' with just one degree of freedom. Despite simplicity, it took us (2 people, me for software and a colleague for electronics and mechanics) around half a year of occasional work to get it done. Nevertheless, my friends in Ukraine report this device is still in field, they use it up to now without any complaints rising.

Problem 4 ver. 4: optimization

December 18th, 2009 by Ivan Lakhturov | 0 Category: Programming | Tags: |

Find the largest palindrome made from the product of two 3-digit numbers.

And the last scratch for now. It is possible to prove that 11 divides a palindromic number. Indeed,

N = \sum_{i=0}^k (10^{2k-i+1} d_i + 10^i d_i) = \sum 10^i d_i (10^{2(k-i)+1} + 1) = \sum 10^i d_i m_i

and here m_i is a multiple of 11 (divisibility by 11 criterion).

The factor 11 can belong to a - and in this case we step just 1 in b. But if 11 doesn't divide a, then we can increase b by 11 each time.

  1.         (define (find-largest-palindrome-using-11 k)
  2.            (let ([m (- (^ 10 k) 1)] [m/10 (^ 10 (- k 1))])
  3.              (let ([m-11 (* 11 (div m 11))])
  4.                (define (iter a b largest-palindrome)
  5.                  (if (< a m/10) largest-palindrome
  6.                      (let ([step (if (= 0 (mod a 11)) 1 11)]
  7.                            [next-a-11? (= 0 (mod (- a 1) 11))])
  8.                        (if (< b m/10) (iter (- a 1) (if next-a-11? m m-11) largest-palindrome)
  9.                            (let ([n (* a b)])
  10.                              (if (<= n largest-palindrome) (iter (- a 1) m largest-palindrome)
  11.                                  (if (palindrome-number? n) (iter (- a 1) m n)
  12.                                      (iter a (- b step) largest-palindrome))))))))
  13.                (iter m m 0))))

This speeds up the previous result around ten times, leaving an asymptotic behavior the same. The memory use is the same O(1).

Let's look at results:
k = 2 => N = 9009
k = 3 => N = 906609
k = 4 => N = 99000099
k = 5 => N = 9966006699
k = 6 => N = 999000000999
k = 7 => N = 99956644665999
k = 8 => N = 9999000000009999
...
We could improve our algo drastically, if proven that the sought-for palindrome is less or equal n - \sqrt n (and mirrored). I have the feeling that for even k it is equal. But I don't know how to prove it. (I calculated for k = 10 and this does not hold, N = 99999834000043899999).

Problem 4 ver. 3: optimization

December 17th, 2009 by Ivan Lakhturov | 0 Category: Programming | Tags: |

Find the largest palindrome made from the product of two 3-digit numbers.

An author, however, advises a simpler approach. As we are looking for a palindrome a*b, let's iterate a and b in a top-down direction. After finding some palindrome, impose it as a top boundary for palindromes, that is, iterating in the inner loop for b, we stop when a*b cannot be large than that anymore. If we found a new palindrome, it will replace the boundary. Stop condition is finishing the outer loop in a, i.e. when it drops to 2-digits number (k-1, generally speaking).

  1.         (define (find-largest-palindrome-with-cutoffs k)
  2.            (let ([m (- (^ 10 k) 1)] [m/10 (^ 10 (- k 1))])
  3.              (define (iter a b largest-palindrome)
  4.                (if (< a m/10) largest-palindrome
  5.                    (if (< b m/10) (iter (- a 1) m largest-palindrome)
  6.                        (let ([n (* a b)])
  7.                          (if (<= n largest-palindrome) (iter (- a 1) m largest-palindrome)
  8.                              (if (palindrome-number? n) (iter (- a 1) m n)
  9.                                  (iter a (- b 1) largest-palindrome)))))))
  10.              (iter m m 0)))

Complexity in memory now is just O(1). Performance complexity by my impression is better than in the previous variant. The outer loop has n - n/10 steps, so it cannot be less than O(n). Assuming that a desired palindrome (left half of it, actually) lies close to n - \sqrt n (which should be proved, strictly speaking), we make no more than n \cdot \sqrt n = n^{3/2} operations until find it, and no more than the same n^{3/2} afterwards.

This is the worst case, however, and I hope that we find some worse-than-ideal palindrome quick enough. Suppose, we can use the estimate n - \sqrt n ab origin, i.e. the inequality f \cdot g < \sqrt n \cdot \sqrt n = n holds, where f = n - a, g = n - b. Then we can calculate an estimate of operations as area under a curve y = n / x:

\int_1^n \frac n x dx = n \cdot \ln n

So, the actual algo performance is between O(n \ln n) and O(n^\frac 3 2).

Problem 4 ver. 2: optimization

November 29th, 2009 by Ivan Lakhturov | 0 Category: Programming | Tags: |

Find the largest palindrome made from the product of two 3-digit numbers.

Last time we had a straightforward algo with O(n^2) complexity and at least O(n) memory use. Now let's enhance that. Instead of iterating over multipliers it's reasonable to iterate over palindromes, starting from the largest. I.e. over sequence 999999, 998899, 997799, and so on.

Remark. The largest product of two 3-digit numbers is 999 * 999 = 998001. So, in principle, we could start from the palindrome 997799. But this saves just 2 iterations.

Having a palindrome m, we factorize it and look at all the subsets of the factorization. Assume, we have one subset already. Let's name the product of those factors as p. If this number p has k digits (k = 3 for now) and the number m/p has k digits, than we found the palindrome, which is a product of two k-digit numbers.

In Scheme that will be written as:

  1.         (define (find-largest-palindrome-via-factorization k)
  2.            (define (correct-length? m) (= (length (digits m)) k))
  3.            (define (iter l) (let* ([n (make-number-from-digits (append (reverse l) l))]
  4.                                    [factors (map mul-list (subsets (factorize n minimal-factor-sqrt-complexity)))]
  5.                                    [factors (filter correct-length? factors)]
  6.                                    [factors (filter (lambda (m) (correct-length? (/ n m))) factors)])
  7.                               (if (null? factors) (iter (digits (- (make-number-from-digits l) 1))) n)))
  8.            ;(display (list n '= (car factors) '* (/ n (car factors)))))))
  9.            (iter (one-number-multiple-times 9 k)))

Here I used a few new util functions:

  1.         (define (make-number-from-radix list k)
  2.            (define (iter l f) (if (null? l) 0 (+ (* (car l) f) (iter (cdr l) (* f k)))))
  3.            (iter list 1))
  4.          (define (make-number-from-digits list) (make-number-from-radix list 10))

which make numbers out of their base-k representation.

Complexity now is hard to calculate. The worst case scenario gives quite a bad upper boundary. However, the worst case will never be realized.

Looking at what it gives out (9009, 906609, 99000099, 9966006699, 999000000999, ...), I could guess that the required palindrome is found after roughly \sqrt n iterations. So, in total I hope for less than O(n^2) complexity.

The memory use depends on factorizations - we store one whenever a palindrome is taken and lose it when proceed with the next palindrome.

Real-time ECG-generator

July 28th, 2009 by Ivan Lakhturov | 0 Category: Programming | Tags:

Some years ago I accomplished a project of the real-time ECG-generator (the text is in Russian) for Spectromed-UA. I wrote a soft part in Delphi, and another guy dealt with an electronics part.

The device is connected to PC and sends out a signal via LPT to a DAC outside. A signal could be rectangular (meander), sinusoidal and ECG-like. (ECG is the electrocardiogram by the way). The 'heartbeat' of the latest one can be modulated in time. A subprogram to play out real ECG was included. Some noise modulation was included as well.

That was designed to test cardio-analyzers and similar devices. Small and neat project, as I remember. There was no support for the most pathological arrhythmias, however.

All subsets of a set

July 2nd, 2009 by Ivan Lakhturov | 0 Category: Programming | Tags: |

As I already posted in Scheme, a function computing all subsets of a set would be:

  1. #!r6rs
  2. (import (rnrs))
  3.  
  4. (define (subsets set)
  5.   (define (recursion set rest) (if (null? set) (list rest)
  6.                                    (let ([head (car set)] [tail (cdr set)])
  7.                                      (append (recursion tail rest) (recursion tail (cons head rest))))))
  8.   (recursion set '()))
  9.  
  10. (display (subsets '(a b c d)))

The same in Haskell:

  1. s = "abcd"
  2.  
  3. subsets s = ssets (s) []
  4. ssets [] r = [reverse(r)]
  5. ssets (x:xx) r = ssets xx r ++ ssets xx (x:r)
  6.  
  7. main = do
  8.         putStrLn " Set: "
  9.         print s
  10.        
  11.         putStrLn " Subsets: "
  12.         print (subsets s)

For imperative languages I'd rather prefer bitwise approach. Here is in C#:

  1. using System;
  2.  
  3. namespace Subsets
  4. {
  5.     class Program
  6.     {
  7.         static void Main()
  8.         {
  9.             string elements = "abcd";
  10.             for (ulong i = 0; i < Math.Pow(2, elements.Length); i++)
  11.             {
  12.                 ulong set = i;
  13.                 for (int j = 0; j < elements.Length; j++, set >>= 1)
  14.                     if ((set & 0x01) == 1)
  15.                         Console.Write(elements[j]);
  16.                 Console.WriteLine();
  17.             }
  18.         }
  19.     }
  20. }

How to remove "Please wait while the document is being prepared for reading" message in Acrobat

May 30th, 2009 by Ivan Lakhturov | 0 Category: Programming | Tags: |

It really bothered me. So, I googled. All links give the same solution: one, two, three.

Problem 3: a note

May 5th, 2009 by Ivan Lakhturov | 0 Category: Programming | Tags:

Find the largest prime factor of a composite number.

The problem of integer factorization is one of the most important in the number theory. Last time I implemented a classical algorithm with O(\sqrt{n}) complexity. The author of the Project Euler website suggests a small improvement --- iterating over only odd numbers, but I consider this as too tiny thing to do.

As regards the problem of factorization, I'd rather look in special literature, what are the known approaches (and I'll do that later, let's switch to the next one).

Problem 2 ver. 2, 3, 4: logarithmic complexity

April 17th, 2009 by Ivan Lakhturov | 0 Category: Programming | Tags: |

Find the sum of all the even-valued terms in the Fibonacci sequence which do not exceed four million

The last time we had the straightforward O(n) solution: building a sequence, filtering out even values and adding them. We can improve a bit, noticing that actually, every third member of the Fibonacci sequence is even. We don't check then for evennes, but just jump over three components each time. This version 2 (I don't publish it here) should be several times faster, but still is O(n) in performance.

We can also express a member of the Fibonacci sequence via the third and sixth members from behind: F_{n} = 4 F_{n-3} + F_{n-6} and compute those values as the values of a new sequence: E_n = 4 E_{n-1} + E_{n-2}. This version 3 is essentially the same as the previous one and again, I don't publish it here.

The drastic improvement is obtained using the expression \sum_{k=0}^{n} F_{3k} = \frac{F_{3n+2}-1}{2} (I've added it and a proof to the wikipedia article, but they immediately reverted my changes as "unsourced" --- this is pathetic). Now the sum is obtained just computing one Fibonacci member, and this can be done with O(log n).

Indeed, we can compute a Fibonacci member exponentiating the appropriate matrix, and this exponentiation, just like usual one, can be done with O(log n). I prefer this solution over using the golden ratio exponentiation formula (again logarithmic complexity), because only integer-operations are involved. So, this is the version 4 of the solution.

  1.         (define (fibonacci-member-logarithmic n) (matrix-2d-a12 (^-2d fibonacci-matrix n)))
  2.          (define (fibonacci-sum-even n) (/ (- (fibonacci-member-logarithmic (+ n 2)) 1) 2))

I quickly outlined a class for 2D matrices and operations with it:

  1.         (define-record-type matrix-2d (fields a11 a12 a21 a22))
  2.          (define identity-matrix-2d (make-matrix-2d 1 0 0 1))
  3.          (define fibonacci-matrix (make-matrix-2d 1 1 1 0))
  4.          (define (*-2d A B) (let ([a11 (matrix-2d-a11 A)]
  5.                                   [a12 (matrix-2d-a12 A)]
  6.                                   [a21 (matrix-2d-a21 A)]
  7.                                   [a22 (matrix-2d-a22 A)]
  8.                                   [b11 (matrix-2d-a11 B)]
  9.                                   [b12 (matrix-2d-a12 B)]
  10.                                   [b21 (matrix-2d-a21 B)]
  11.                                   [b22 (matrix-2d-a22 B)])
  12.                               (make-matrix-2d (+ (* a11 b11) (* a12 b21)) (+ (* a11 b12) (* a12 b22))
  13.                                               (+ (* a21 b11) (* a22 b21)) (+ (* a21 b12) (* a22 b22)))))
  14.          (define (^-2d-linear A n) (apply-n-times identity-matrix-2d n (lambda (x) (*-2d x A))))
  15.          (define (^-2d-logarithmic A n) (if (= n 0) identity-matrix-2d
  16.                                             (if (odd? n) (*-2d A (^-2d-logarithmic A (- n 1)))
  17.                                                 (let ([B (^-2d-logarithmic A (div n 2))]) (*-2d B B)))))
  18.          (define ^-2d ^-2d-logarithmic)

The solution is O(1) in memory and O(log n) in performance - of course, where n denotes the index of a number in the Fibonacci sequence. And we have been questioned about the cutset, where members of a sequence are less than certain number. Then an additional function (closest-fibonacci-index) comes in handy (see the wiki for explanation):

  1.         (define golden-ratio (/ (+ 1 (sqrt 5)) 2))
  2.          (define (closest-fibonacci-index f) (round (log (* f (sqrt 5)) golden-ratio)))
  3. (define (solution-2-optimized-3 n) (fibonacci-sum-even (closest-fibonacci-index n)))

The final touch is asking ourselves about complexity of the (log) function. Well, it can be computed fast enough not to spoil complexity of the algo's main part.