Showing posts with label beauty. Show all posts
Showing posts with label beauty. Show all posts

Sunday, November 29, 2015

Shortest path touching a circle


This came up a week or so ago in a discussion with a lab mate. The governing principle is well-known from physics, but I was too lazy to find a derivation online. Later on, I had an idea and wanted to give it a try, so here goes.

We're interested in the shortest path starting at point $a$ to point $b$ with the requirement that it intersects a circle of radius $r$ centered at point $c$, and does so before stopping at $b$. When the circle intersects the line segment $\overline{ab}$, the segment coincides with the shortest path. Hence, we are interested in paths that reflect off the circle, just like a ray of light does when it hits a shiny surface. I'll be referring to the figure to the right.

Eventually, we're interested in a statement involving the angle of incidence $\theta$. However, I found it easier to work instead with the central angle $\theta'$. We might as well parameterize the path by the point of incidence $x$ and write the length as:

\[ f(x) = |\overline{ax}| + |\overline{xb}|. \]

Now, what do we know about each of $\overline{ax}$ and $\overline{xb}$? Assume $d_a$ and $d_b$ are the distances from $c$ to $a$ and $b$, respectively. Let's look at $\triangle{cxa}$. By the law of cosines, we have that:

\[ |\overline{ax}|^2 = d_a^2 + r^2 - 2  d_a  r  \cos{\theta'}. \]
Likewise for $\triangle{cxb}$, where $\phi' = \angle{acb}$, we get:
\[ |\overline{xb}|^2 = d_b^2 + r^2 - 2  d_b  r  \cos{(\phi' - \theta')}. \]

It's quite disappointing that we don't obtain nice expressions for $|\overline{ax}|$ and $|\overline{xb}|$ to plug into $f(x)$. But, since we're only interested in minimizing $f$, we might hope that finding the derivative will get us around that. Let's start by rewriting $f$ as:

\[ f(x) = \sqrt{|\overline{ax}|^2} + \sqrt{|\overline{xb}|^2}. \]

We can then write the derivative as:

\[ \frac{\partial f(x)}{\partial \theta'} = \frac{1}{2\sqrt{|\overline{ax}|^2} }\frac{\partial |\overline{ax}|^2}{\partial \theta'} + \frac{1}{2\sqrt{|\overline{xb}|^2}.}\frac{\partial |\overline{xb}|^2}{\partial \theta'}. \]

Plugging in $\frac{\partial |\overline{ax}|^2}{\partial \theta'} = 2d_ar\sin{\theta'}$ and $\frac{\partial |\overline{xb}|^2}{\partial \theta'} = -2d_br\sin{(\phi'-\theta')}$ we get:

\[ \frac{\partial f(x)}{\partial \theta'} = \frac{d_ar\sin{\theta'}}{|\overline{ax}|} - \frac{d_br\sin{(\phi' - \theta')}}{|\overline{xb}|}. \]

Setting $\frac{\partial f(x)}{\partial \theta'} = 0$, cancelling $r$ and rearranging, we find that:

\[ \frac{d_a\sin{\theta'}}{|\overline{ax}|} = \frac{d_b\sin{(\phi' - \theta')}}{|\overline{xb}|}. \]

It would really help to realize that $d_a\sin{\theta'} = |\overline{aa'}|$ and $d_b\sin{(\phi'-\theta')} = |\overline{bb'}|$, where $a'$ and $b'$ are the projections of $a$ and $b$, respectively, on $\overrightarrow{cx}$. Making this substitution we get:

\[ \frac{|\overline{aa'}|}{|\overline{ax}|} = \frac{|\overline{bb'}|}{|\overline{xb}|}. \]

Letting $\phi = \angle axb$, this is the same as:

\[ \sin{\theta} = \sin{(\phi - \theta)}. \]

Or,

\[ \theta = \phi - \theta. \]

Which says that the angle of incidence should be equal to the angle of reflection, for the path to be optimal. Which is already known.

Update 01/14/16: There remains the issue of determining the point $x$ that minimizes the shortest path defined by $f$. I found it easier to work with angles $\alpha = \angle{cax}$ and $\beta = \angle{cbx}$. Applying the law of sines in $\triangle{cxa}$ and $\triangle{cxb}$ we find that:

\[ \sin{(\pi - \theta)} = \sin{\theta} = \frac{d_a}{r}\sin{\alpha}, \quad \sin{(\phi - \theta)} = \frac{d_b}{r}\sin{\beta}.\]

Since the point $x$ we are interested in makes $\theta = \phi - \theta$, we get:

\[ d_a\sin{\alpha} = d_b\sin{\beta}. \]

In a way, this equation only describes the angle of incidence from $a$ or $b$ to points on the circle. We still need a second equation to ensure these two angles correspond to a single point of incidence. This can be achieved by examining $\triangle{abx}$. Letting $\alpha' = \angle{cab}$ and $\beta' = \angle{cba}$ we can write:

\[ (\alpha' - \alpha) + (\beta' - \beta) + \phi = \pi. \]

Rewriting $\phi = 2 \theta$ and rearranging we get:

\[ \beta = (\alpha' + \beta' - \pi) - \alpha + 2\theta. \]

Noting that $\theta = \arcsin{(\frac{d_a}{r}\sin{\alpha})}$, we can now eliminate $\beta$ using the first equation to get an equation for $\alpha$ only, and the same can be written for $\beta$:

\[ \alpha = (\alpha' + \beta' - \pi) + 2 \arcsin{(\frac{d_a}{r}\sin{\alpha})} - \arcsin{(\frac{d_a}{d_b}\sin{\alpha)}}. \]

Other than a numerical approach, it is plausible to assume $\alpha$ is small especially when $d_a \gg r$. This might justify linearizing both the sines and arcsines to get something like:

\[ \alpha \approx \frac{\alpha' + \beta' - \pi}{1 + \frac{d_a}{d_b} - 2 \frac{d_a}{r}}. \]

Wednesday, January 26, 2011

A lightweight anonymous visitor for Java collections

I got myself into a situation where I really wished that Java collections accepted a visitor interface of some kind so I could define one on the fly and get my job done. Alas, I decided to implement the utility myself and here's the result.

public interface IVisitor<T> {
void visit(T item);
}

public class CollectionUtils {
public static<T> void applyVisitor(Collection<T> collection, IVisitor<T> visitor) {
for (T item : collection)
visitor.visit(item);
}
}
A typical usage example would be:
public static void main(String[] args) {
CollectionUtils.applyVisitor(Arrays.asList(1, 2, 3, 4, 5), new IVisitor<Integer>() {
public void visit(Integer x) {
System.out.println(x);
}
});
}

Sunday, October 24, 2010

Efficient enumeration of all integers with a given pop count

Population count is the number of '1' bits in the binary representation of an integer.

The basic trick we employ is to get the next higher number with the same number of 1-bits, which we borrow from the Hacker's Delight (whole book). Below is a Java implementation of all 4 version of the snoob function.

public static int snoob1(int x) {
int r = x + (x & -x);
return r | ((x ^ r) >>> (2 + Integer.numberOfTrailingZeros(x)));
}

public static int snoob2(int x) {
int s = x & -x, r = x + s;
return r | ((x ^ r) >>> (33 - Integer.numberOfLeadingZeros(s)));
}

public static int snoob3(int x) {
int r = x + (x & -x);
return r | ((1 << (Integer.bitCount(x ^ r) - 2)) - 1);
}

public static int snoob4(int x) {
int s = x & -x, r = x + s;
return r | (((x ^ r) >> 2) / s);
}
We utlize this formula to implement the method below, where the width parameter is added for convenience.
public static void printAllIntegersOfWidthAndPop(int w, int n) {
if (n <= 0 || n > w || w > 32) return;
int x = (1 << n) - 1, g = x << (w - n), c = 0;
while (true) {
String s = Integer.toBinaryString(x);
while(s.length() < w) s = "0" + s;
System.out.println(++c + "\t" + s);
if (x == g) break;
else x = snoob*(x);
}
}
It is easy to figure out there will be Choose(w, n) such numbers. We know where the sequence starts and since we also know where it stops, we don't need to compute this number.

If you'd like to learn how to find the number of leading/trailing zeros or the pop count or learn about more cool bit twiddling hacks you can consult the book above (which the java.lang.Integer implementation of these methods is based on) or this magnificent web page.

Saturday, July 17, 2010

Generating combinations in lexicographical order using Java

Below is a Java port of the algorithm by James McCaffrey as presented in the MSDN article Generating the mth Lexicographical Element of a Mathematical Combination.

Please do take into consideration that this implementation only uses int as Java does not allow array indexing with long. This means that the valid input range is more restricted. Watch out for overflows!

/**
* Based on the Combinadic Algorithm explained by James McCaffrey
* in the MSDN article titled: "Generating the mth Lexicographical
* Element of a Mathematical Combination"
* <http://msdn.microsoft.com/en-us/library/aa289166(VS.71).aspx>
*
* @author Ahmed Abdelkader
* Licensed under Creative Commons Attribution 3.0
* <http://creativecommons.org/licenses/by/3.0/us/>
*/
public class Combinations {
/** returns the mth lexicographic element of combination C(n,k) **/
public static int[] element(int n, int k, int m) {
int[] ans = new int[k];

int a = n;
int b = k;
int x = (choose(n, k) - 1) - m; // x is the "dual" of m

for (int i = 0; i < k; ++i) {
a = largestV(a, b, x); // largest value v, where v < a and vCb < x
x = x - choose(a, b);
b = b - 1;
ans[i] = (n - 1) - a;
}

return ans;
}

/** returns the largest value v where v < a and Choose(v,b) <= x **/
public static int largestV(int a, int b, int x) {
int v = a - 1;

while (choose(v, b) > x)
--v;

return v;
}

/** returns nCk - watch out for overflows **/
public static int choose(int n, int k) {
if (n < 0 || k < 0)
return -1;
if (n < k)
return 0;
if (n == k || k == 0)
return 1;

int delta, iMax;

if (k < n - k) {
delta = n - k;
iMax = k;
} else {
delta = k;
iMax = n - k;
}

int ans = delta + 1;

for (int i = 2; i <= iMax; ++i) {
ans = (ans * (delta + i)) / i;
}

return ans;
}
}
The code below produced the output that follows:
public static void main(String[] args) {
int n = 5, k = 3;
int total = choose(n, k);
for(int i = 0; i < total; i ++) {
for(int x : element(n, k, i))
System.out.print(x + " ");
System.out.println();
}
}

0 1 2
0 1 3
0 1 4
0 2 3
0 2 4
0 3 4
1 2 3
1 2 4
1 3 4
2 3 4

Monday, June 21, 2010

G/G/1 Queue Model Simulation in Java

In this post, we present an object-oriented design and implementation of an event-driven G/G/1 queue model simulation using Java. The lecture notes on Computer System Analysis by Raj Jain were very helpful and are highly recommended. In particular, we would like to reference the introductory lectures on Simulation Modeling and Queueing Theory.

Please note that this implementation is provided as a guide/starting point and is not, by any means, complete. We preferred a simple design while keeping in mind where you may wish to extend it.

Update: Download the Eclipse project here.

An event-driven simulation operates by generating and processing events through time. For our queue model, we have two types of events: arrivals and departures or service completion. It is also necessary to determine which events should happen first.

public class Event implements Comparable<Event> {
protected double time;
protected int code;

...

public int compareTo(Event e) {
return Double.compare(time, e.time);
}
}
While the design will not make any assumptions about the interarrival or service time distributions, we still need a suitable way to represent them and a couple of concrete implementations for testing.
public abstract class Distribution {
public abstract double generateRV();
}

public class UniformDistribution extends Distribution {
double a, b;

...

public double generateRV() {
return a + rand.nextDouble() * (b - a);
}
}

public class ExponentialDistribution extends Distribution {
double lambda;

...

// Generating exponential variates.
public double generateRV() {
return -1/lambda * Math.log(rand.nextDouble());
}
}

public class NormalDistribution extends Distribution {
double mu, segma;

...

public double generateRV() {
return mu + rand.nextGaussian() * segma;
}
}
Now, we should be ready to implement the queue class. We preferred to keep the queue simple by moving data collection into a separate arbitrary observer.
/**
* @author Ahmed Abdelkader
* Licensed under Creative Commons Attribution 3.0
* <http://creativecommons.org/licenses/by/3.0/us/>
*/
public class GG1Q {
protected Distribution arrivalDistribution;
protected Distribution serviceDistribution;
protected double t;
protected PriorityQueue<Event> eventQueue = new PriorityQueue<Event>();
protected int customers;
protected QueueObserver observer;

...

public void run(double duration) {
eventQueue.add(new Event(t + arrivalDistribution.generateRV(), Event.ARRIVAL));
while(t < duration) {
Event e = eventQueue.poll();
t = e.time;
switch(e.code) {
case Event.ARRIVAL:
customers++;
eventQueue.add(new Event(t + arrivalDistribution.generateRV(), Event.ARRIVAL));
if(customers == 1)
eventQueue.add(new Event(t + serviceDistribution.generateRV(), Event.SERVICE));
break;
case Event.SERVICE:
customers--;
if(customers > 0)
eventQueue.add(new Event(t + serviceDistribution.generateRV(), Event.SERVICE));
break;
}
if(observer != null)
observer.stateChanged(this, e);
}
}

...
}
We define the observer interface and implement two sample observers: one for estimating the queue length PDF and the other for the waiting time CDF. A composite observer allows more than one observer to collect data of a single run.
public interface QueueObserver {
void stateChanged(GG1Q q, Event e);
void printStats();
}

public class CompositeQueueObserver implements QueueObserver {
protected ArrayList<QueueObserver> observers = new ArrayList<QueueObserver>();

public void addObserver(QueueObserver observer) {
observers.add(observer);
}

public void stateChanged(GG1Q q, Event e) {
for(QueueObserver observer : observers)
observer.stateChanged(q, e);
}

public void printStats() {
for(QueueObserver observer : observers)
observer.printStats();
}
}

public class QueueLengthQueueObserver implements QueueObserver {
protected TreeMap<Integer, Integer> lengthFrequencies = new TreeMap<Integer, Integer>();
protected int total;

public void stateChanged(GG1Q q, Event e) {
if(e.getCode() != Event.ARRIVAL) return;
Integer length = lengthFrequencies.get(q.getLength());
if(length == null) length = 0;
lengthFrequencies.put(q.getLength(), length + 1);
total++;
}

public void printStats() {
System.out.println(getClass().getSimpleName());
for(int length : lengthFrequencies.keySet())
System.out.println(length + "\t" + 1.0*lengthFrequencies.get(length)/total);
}
}

public class WaitingTimeQueueObserver implements QueueObserver {
protected ArrayList<Double> waitingTimes = new ArrayList<Double>();
protected int arrivalIndex, serviceIndex;
protected HashMap<Integer, Double> arrivalTimes = new HashMap<Integer, Double>();

public void stateChanged(GG1Q q, Event e) {
switch(e.getCode()) {
case Event.ARRIVAL:
arrivalTimes.put(arrivalIndex++, e.getTime());
break;
case Event.SERVICE:
waitingTimes.add(e.getTime() - arrivalTimes.get(serviceIndex++));
break;
}
}

public void printStats() {
System.out.println(getClass().getSimpleName());
if(waitingTimes.size() == 0) return;
double acc = 0;
Collections.sort(waitingTimes);
for(int i = 1, j = 0; i <= 10; i++) {
while(acc < i/10.0 && j < waitingTimes.size()) {
acc += 1.0/waitingTimes.size();
j++;
}
System.out.println(waitingTimes.get(j-1) + "\t" + i/10.0);
}
}
}
The following test program produced the output below:
public class Main {
public static void main(String[] args) {
GG1Q q = new GG1Q(new ExponentialDistribution(100.0/3600), new UniformDistribution(1, 10));
QueueObserver observer = new QueueLengthQueueObserver();
q.setObserver(observer);
q.run(1000);
observer.printStats();
}
}

QueueLengthQueueObserver
Queue length PDF:
1 0.47058823529411764
2 0.23529411764705882
3 0.058823529411764705
4 0.058823529411764705
5 0.11764705882352941
6 0.058823529411764705

Wednesday, April 28, 2010

GeoTraffic & GeoKeywords: Google Analytics custom reports for fun and profit

I've been using Google Analytics for 2 years to track the traffic on this blog. It's really interesting to see which posts receive more attention and what traffic sources and keywords generated how much traffic on any one day. This is specially important to me since the majority of the traffic to my blog comes from search engines a.k.a. google (organic).

However, when you really look into the traffic tracking thing, you'll find that the default reports which come out-of-the-box with Google Analytics don't help answer certain questions. This is more evident on a modest personal blog than it would be for a hot website like stackoverflow, for example. For your blog, you'd actually want to know who visited the blog. I mean, you'd like to push the limits of anonymity.

The main missing information in the default Analytics reports have to do with location. While you're able to know how many visits were generated from each country in addition to some useful statistics like the average time on website and pages/visit, there is still something missing.

I wanted to be able to answer these 2 critical questios:
1) Where does the direct traffic come from? and which pages are requested?
2) Who is searching for what?

Thanks to the Google Analytics team, we are now able to create our own custome reports to project the data whichever way we want. Once I found out, I created 2 custom reports to answer my 2 questions.

For the first question, the GeoTraffic report is the answer. The main dimension would be the Source. Next, we drill down towards: Country/Territory -> City -> Page. The main metric is Pageviews, then Pages/Visit and Avg. time on page.

For the second question, the GeoKeywords report is the answer. This time, the main dimension is the Country/Territory then we drill down to: Keyword -> City. For this report, I preferred the main metric to be Avg. time on page then Pages/Visit and Unique Visitors.

Now, I'm able to answer my questions, and I've been mainly interested in the first one: where the direct traffic comes from. The reason for that is that I've been waiting for something. I may talk about that later. I guess you're going to find it useful ;)

Friday, February 5, 2010

Introducing Google App Engine - All in One

Google App Engine lets you run your web applications on Google's infrastructure e.g. GFS and BigTable. App Engine applications are easy to build, easy to maintain, and easy to scale as your traffic and data storage needs grow. With App Engine, there are no servers to maintain: You just upload your application, and it's ready to serve your users... more docs. An alternative introduction is available on Wikipedia.

I compiled a list of videos that should get your engines up and running on this exciting web framework:

Campfire One - Introducing Google App Engine:

  1. Pt. 1 (9:10)
  2. Pt. 2 (12:34)
  3. Pt. 3 (13:19)
  4. Pt. 4 (7:44)
  5. Pt. 5 (5:55)
  6. Pt. 6 (8:04)
Overviews:
  1. Google App Engine - Early Look at Java Language Support (7:38)
  2. Overview of Google Web Toolkit (4:10)
  3. Getting Started with App Engine in Eclipse (5:07)
Google I/O 2008:
  1. Google I/O 2008 - Working with Google App Engine Models (1:00:32)
  2. Google I/O 2008 - Building Quality Apps on App Engine (48:43)
  3. Google I/O 2008 - Engaging User Experiences with App Engine (45:32)
  4. Google I/O 2008 - Python, Django, and App Engine (57:09)
Google I/O 2009:
  1. Google I/O 2009 - A Preview of Google Web Toolkit 2.0 (1:00:53)
  2. Google I/O 2009 - App Engine: Now Serving Java (55:00)
  3. Google I/O 2009 - Groovy and Grails in App Engine (1:00:14)
  4. Google I/O 2009 - Java Persistence & App Engine Datastore (1:09:32)
  5. Google I/O 2009 - ThoughtWorks on App Engine for Java (1:04:18)
Check out the project homepage and the developer's guide for more and subscribe to the Google App Engine Blog.

Saturday, January 23, 2010

On the Fairness of Reservoir Sampling

Reservoir sampling is a family of randomized algorithms for randomly choosing K samples from a list of S items, where S is either a very large or unknown number.

A very elegant algorithm titled Algorithm R by Alan G. Waterman, is summarized as follows:

Fill up the 'reservoir' with the first k items from S
For every item S[j] where j > K
Choose an integer r between 0 and j
If r < K then replace element r in the reservoir with S[j]
One very interesting discussion with a friend led me to this problem. In this post we are going to prove that at all times, the probability of each processed item to be in the reservoir is the same for all items. In other words, after each iteration and when the algorithms terminates, all processed items will have the same probability of being included.

To initialize the reservoir, the first K items are included. At this point of time, each item is included by a probability of 1.

Later on, to process item number A, where A > K, we include it by a probability of K / A. (1)

For any of the K items in the reservoir, it will remain in the reservoir after item A is processed only in 2 cases:
1) Item A does not get included. This has a probability of ( A - K ) / A = 1 - K / A
2) Item A gets included but it does not replace the item in question, i.e. it can replace any of the other ( K - 1 ) items in the reservoir. This has a probability of ( K / A ) * [ ( K - 1 ) / K ] = ( K - 1 ) / A

So each of the K items remains in the reservoir by a probability of 1 - K / A + ( K - 1 ) / A = 1 - 1 / A

This is the same as the probability of A not replacing our item. Since the probability of A replacing any one item is 1 / A. The complement is directly found as 1 - 1 / A

Now, let P( A, B ) be the probability of item A still being included in the reservoir after item B is processed, where B >= A. Without loss of generality, we may assume that B is the next item to be processed.

For item A to remain in the reservoir after item B is processed, item A must have been included up to the point where B is to be processed. Equivalently, item A was still included after item (B - 1) was processed. In addition, for A to remain in the reservoir B must not replace it

From the discussion above, it follows that:
P( A, B ) = [ 1 - 1 / B ] * P( A, B - 1 )

Which can be expanded as:
P( A, B ) = [ 1 - 1 / B ] * [ 1 - 1 / ( B - 1 ) ] * ... * [ 1 - 1 / ( A + 2 ) ] * [ 1 - 1 / ( A + 1 ) ] * p( A, A )

But from (1):
P( A, A ) = K / A

As a result:
P( A, B ) = [ 1 - 1 / B ] * [ 1 - 1 / ( B - 1 ) ] * ... * [ 1 - 1 / ( A + 2 ) ] * [ 1 - 1 / ( A + 1 ) ] * K / A

But,
[ 1 - 1 / ( A + 1 ) ] = A / ( A + 1 )

Therefore:
P( A, B ) = [ 1 - 1 / B ] * [ 1 - 1 / ( B - 1 ) ] * ... * [ 1 - 1 / ( A + 2 ) ] * [ A / ( A + 1 ) ] * K / A
P( A, B ) = [ 1 - 1 / B ] * [ 1 - 1 / ( B - 1 ) ] * ... * [ 1 - 1 / ( A + 2 ) ] * K / ( A + 1 )

Again:
P( A, B ) = [ 1 - 1 / B ] * [ 1 - 1 / ( B - 1 ) ] * ... * K / ( A + 2 )

We can see that this recurrence reduces to:
P( A, B ) = K / B

This is the same as the probability of item B being included. In addition, P( A, B ) is not a function of A, it only depends on B, which is the number of elements processed so far.

This means that for the next item to be processed it will have the same probability of being included as all the items that were processed before it. By maintaining this property, when the algorithm terminates, all items will have the same probability of being included in the reservoir, regardless of the size of the list.

Friday, August 29, 2008

Escapement mechanisms in mechanical clocks

I was fascinated by the simplicity and elegance of these mechanisms, yet it's not comprehensible at the first glance which adds to its charm. Illustrated above is the grasshopper escapement which was invented by British clockmaker John Harrison around 1722. Read more about that here.

Tuesday, August 12, 2008

Watching Beijing 2008 Olympic Games

it's very interesting to watch the competitors pushing the limits of our perception of human capabilities both physical and mental, as they strive for perfection and withstand termendous stress, being watched by millions of people worldwide, and also how they represent their nations, attempting to bring back as much glory as possible, and to be rewarded with medals and world records, with the national anthem playing in the background and the flag hanging above their heads.

Friday, April 11, 2008

Native Deen - Reviving Islamic Rap

Muslim brotha's did it again. Native Deen are a Muslim musical group from the United States. They consist of three young Muslim men who were born and raised in America. Joshua Salaam, Naeem Muhammad, and Abdul-Malik Ahmad who grew up in Washington, DC. Their music seeks to inspire young people to keep their faith amid the pressures and temptations of modern life.

Many Muslims believe that string and wind instruments should be avoided in Islam. In order to please the widest audience, the group does not use any string or wind instruments in their music. The main instruments are drums, synthesized percussion instruments, and vocals.

Check their home page http://nativedeen.com/ and don't miss the clip: I am not afraid to be alone, if ALLAH is by ma side (lyrics). If you found yourself interested, you can watch that one too: Small Deeds (lyrics) - put a dollar everyday in the sadaka, it maybe small but you do it for the baraka - these combinations produced a very interesting culture.

Their music is produced under the Mountain of Light label, which was founded by Yusuf Islam (previously known as Cat Stevens)

Keep it goin' brotha's!

Source Wikipedia.

Saturday, January 12, 2008

Early in the morning, preparing for the exams...

well it's been some time since i last wake up that early and i have to say it's very quite and clear now, very beautiful indeed, i open the window and the morning sun covered the room in marvelous colors i didn't see before in my cozy room,

this couldn't have been complete for me without a touch of sadness from Anouar Brahem music, and now it's become so captivating i feel i'm lost in all that beauty,

approaching the end of the semester, the first exam's just tomorrow, starting with Operating Systems, i've much to revise, we covered a very reasonable amount in the course, maybe a little more practice and it'd have been nearly perfect,

this semester has been so full, and i'm quite satisfied with the things i did and the experiences i gained, maybe i'll have to tell you about that, but let's keep it for later...

Wednesday, January 2, 2008

El-Tanbura, seductive folk melodies of the mythical Simsimiyya


what can i say! it just struck me when i first listened to the very fine tunes they played, i couldn't help playing the songs again and again as if not believing that such melodies can exist in the real world, it was like a journey through the mysteries of the Arabian Nights, very genuine and very seductive.

the homepage, provides plenty of samples and a very interesting biography that describes the origins of the band and the roots of the fascinating genre they play, it also mentions the myths about the origins of the instrument they use, called Simsimiyya, which adds a little spice to the whole thing,

you can find a complete song here on boomp3.com, i hope you enjoy this unique experience as much as i did.

Wednesday, December 12, 2007

Mathematical Beauty

i believe mathematics is really beautiful, you only need to be shown that beauty if you can't see it for yourself. few gifted ones have the talent and inspiration to expose this beauty for all to see.

Douglas Arnold and Jonathan created a fascinating 3D animation that "depicts the beauty of Möbius transformations and shows how moving to a higher dimension reveals their essential unity. It was one of the winners in the 2007 Science and Visualization Challenge and was featured along with the other winning entries in the September 28, 2007 issue of journal Science. The video, which was first released on YouTube in June 2007, has been watched there by more than a million viewers and classified as a "Top Favorite of All Time" in the Film & Animation category." copied from the project home page.

you can watch the movie here on YouTube.

Tuesday, December 11, 2007

classical music for free

i was so happy to learn about free music websites where you can listen to and download very fine pieces of music. i have always been a fan of classical music as i used to listen to the "Musical Program" on the FM few years ago. among the different flavors of classical music i'd like to mention baroque guitar, very deep and expressive.

i want to thank the people who worked for bringing us these fine pieces of art for free.

musicbakery and musopen are the websites i visited so far.

two different trends i think, musicbakery offer samples and you pay for the whole piece while musopen is all about free music that's available to everybody everywhere. musopen also provides good info about the pieces and the composers, this adds some glamor to the musical experience.

i recommend "Festive Classical" and "Baroque Guitar" on musicbakery, currently i'm exploring musopen, i found some piano concerts for Rachmaninoff and Beethoven which i think will be just great.