blog.sojoodi.com

December 19, 2007

My GMAT Experience!

Filed under: Uncategorized — Sahand @ 8:59 pm

I was busy (read bootcamp!) preparing for and writing the GMAT over the past two weeks. That’s why I haven’t written much lately, but I thought I’d share with you my fun experience with the GMAT!

First thing, this was a really quick decision. I had thought of writing this test for a while, but hadn’t really had the opportunity to do it. So, this time around, as soon as I had time to breathe, I decided to just go for it and get it over with. My strategy was simple: just pick a date 2 weeks from now (well originally I was more ambitious and wanted to do it in one week, but I had a humbling experience). Then everyday, in an all-you-can-eat-buffet-like approach fill your brain with training before it realizes what happened and gets tired!

I stuck to a strict and intensive schedule to make sure I do well on the test. I tried to do a timed test a day, but in the end I had 4 or 5 tests under my belt. I highly recommend the GMATPrep and POWERPREP tests. I also did most of the GMAT Official Review (11th ed, the orange one) and read through some parts of GMAT 800 by Kaplan.

In the final days of prep, I came across this website which I wish I’d seen much earlier: Beat The GMAT. I highly recommend having a look at this. I also took review notes while studying the books and writing tests. I’ve included a part of the document here (GMAT study notes). If you are interested in the full document, send me an email. (I’m doing this to see how many people are actually interested)

Another piece of the strategy was time management. This changes from person to person, but I came up with and used the easy-to-memorize V19-40-30-20/Q17-40-27-20 rule for myself. This cryptic rule basically means: For Verbal, be on question 19 or further when the clock shows that you have 40 minutes left, and be on question 30 or further when it hits 20 minutes. Same for the Quantitative section. I have a spreadsheet for helping with making these rules. If you are interested in seeing and using it, let me know.

Also, make sure you don’t forget preparing for the Analytical Writing Assessment part. There are good resources online (listed at the bottom) for practicing and improving time-management for these essays.

In the end, I had a blast on the test day. And the result was amazing, too. Actually, way better than expected! I had studied hard to get a score above 700. I was pleasantly shocked to see my score in the end. If I were a little better at marketing, I would change the title of this post to: “get an unbelievable GMAT score in two weeks!”

Hope this post is of use.

Last but definitely not least, I’d like to thank Kevin Au and Todd Presswood for sharing with me invaluable information regarding the test.

Additional Material

Email me for this stuff:

  • The full study notes
  • The Time-Management Rule Maker spreadsheet
  • My actual score if you’re interested

Online Resources

Here is a list of webpages that I may have used.

  • http://www.4tests.com/exams/examdetail.asp?eid=31
  • http://www.crack-gmat.com/gmat-test.htm
  • http://www.projectgmat.com/problems.html
  • http://beatthegmat.blogspot.com/2005/08/reflecting-on-my-gmat-experience.html
  • http://www.mba.com
  • http://www.kaptest.com/Business/Business-School/BU_home.html

December 2, 2007

Should a small business give discounts

Filed under: Marketing — Sahand @ 11:33 pm

While reading P. Barrow’s The Best-Laid Business Plans, I came across an interesting argument he had against giving discounts as a small business. The reason for writing this post was to inspect the simple but condensed table of data he provided (”Pricing Ready Reckoner”) which in the space of less than a third of a page, makes a very clear case against discounting.

Here’s the argument. In order to maintain the same level of profit, you would have to sell much more depending on your original Gross Margin and the amount of Discount. The amount of extra sales needed in each case is summarized in the following table as percentages.

  Existing Gross Margins (%)
  5 10 15 20 30 40
% price discount            
1 25% 11% 7% 5% 3% 3%
3 150% 43% 25% 18% 11% 8%
5   100% 50% 33% 20% 14%
10     200% 100% 50% 33%
15       300% 100% 60%

The math is simple if you do not claim a portion of the margin, you have to make up for the difference by increasing sales. But the engineer in me wants to make the calculations more formal:

G=gross margin (%)
R=retail price for unit
D=discount (%)
S=number of items sold, S’=number of items sold (in discounted case)

Without discount we have:
Gross margin=R×G
Cost of Goods Sold per unit=R×(1-G)

With the discount, on the other hand:
Sales revenue per unit=R×(1-D)
Cost of Goods Sold per unit=R×(1-G), remains the same
New gross margin=R×(G-D)

To make the same level of profit
S’×R×(G-D)=S×R×G

Which means we have to sell (S’/S-1) percent more to compensate for the discount:
100×[G/(G-D)-1]

The rest is easy: put the Formula in a spreadsheet and you get that nice table above. There is another table in the book which shows the flip side of the situation: price increase. But I spare you.

As a final note, I believe that you could still make a good case for giving discount on your products/services for a variety of reasons such as building relationship in hopes of recurring customers, gaining market share, etc. However, Paul’s argument is interesting and makes the assumptions that your customers buy from you because of the flexibility, quality, and the service provided. Further, I would like to add to this list the fairness and competitiveness of original pricing.

Simple Search Feature in Rails/MySQL (Part 2)

Filed under: MySQL, Rails — Sahand @ 9:42 pm

I meant to make this post much earlier, but all the start-up fun kept me from doing it. The first part of the post was published on Oct 17 (Simple Search Feature) and covered my Do It Yourself solution for the catalog search feature in Giftify.

The problem with the original indexing scheme was that it created separate “lookup word” entry for words that were inclusive of one other. For example, it would be possible that the word “rose” appeared in the descriptions of gifts 1 and 3 and “rosemary” in 2 and 3. Note that the correct indexing scheme would dictate that all items of “rosemary” are a subset of those of “rose”.

Incomprehensive Indexing

 

One way of fixing this problem is using a query with the LIKE statement in SQL to get all LookupWords that are similar to the actual search term and then perform a complex query, which will have to be created dynamically based on the results of the LIKE query. The complexity of this solution, the shakiness of LIKE/DISTINCT constructs, and the fact that a lot of stuff needs to happen for every search led me to implement a better indexing scheme.

I have mentioned the solution above: when indexing, make sure that the items in “roses” are all included in the set of items associated with “rose”. This way when looking up the word “rose” in the catalog, all three items are returned.

The Ruby implementation of the improved indexing scheme follows. Note that the trivial case of plural words containing the singular ones is handled via pluralize and singularize functions in Rails.

$lookup_word_to_item_map = {}

Item.find(:all).each do |item|
  composite_search = item.name+" "+item.description+" "+item.categories_string

  # take all the words (alpha) and array-ize
  composite_search_array = composite_search.scan(/[a-z]+/).compact.collect {|w| w.singularize}

  # remove all words that are less than 3 letters long
  composite_search_array.collect! {|w| w unless w.size<3}
  composite_search_array.compact!
  composite_search_array.uniq!

  # add data to hash
  composite_search_array.each do |word|
    $lookup_word_to_item_map[word] << item.id unless $lookup_word_to_item_map[word].include? item.id
  end
end

# in ruby str1[str2] returns nil if str1 doesn't contain str2
$lookup_word_to_item_map.keys.each do |baseword|
  extra_items = $lookup_word_to_item_map.keys.collect do |biggerword|
    $lookup_word_to_item_map[biggerword] if biggerword[baseword]
  end
  $lookup_word_to_item_map[baseword] << extra_items
  $lookup_word_to_item_map[baseword].flatten!
  $lookup_word_to_item_map[baseword].compact!
  $lookup_word_to_item_map[baseword].uniq!
end

A quick note on efficiency. The indexing process becomes slower and the index table becomes larger as a result of this scheme, but the trade-off against making on-the-fly search faster is definitely worth it.

Hope this was useful and thanks for dropping by.

November 23, 2007

Exchange Rate Arbiterage Detection

Filed under: Uncategorized — Sahand @ 7:21 pm

Here’s a little brainteaser to think about while commuting to work on the Greyhound bus! (that’s another story maybe for another post).

If you go to x-rates.com or Yahoo Currency Converter you can obtain a table of exchange rates for world’s major currencies. Here’s a sample:


USD U.K. £ CAD Euro AU $
USD 1.00000 2.05639 1.01142 1.48250 0.87440
U.K. £ 0.48629 1.00000 0.49184 0.72092 0.42521
CAD 0.98870 2.03316 1.00000 1.46574 0.86452
Euro 0.67454 1.38711 0.68225 1.00000 0.58981
AU $ 1.14364 2.35177 1.15671 1.69544 1.00000

* (USD to CAD element was changed from 0.98870 to 1.0 in the example below)

The data is essentially a matrix as follows (with a bit of rearranging and reducing the number of currencies):

FX table

C for Canadian Dollar
U for US Dollar
E for Euro
CU: price of 1 Canadian dollar in US dollars as reported in the table
UC: price of 1 US dollar in Canadian dollars as reported in the table

FX-table multiplied by itself

This matrix, in an efficient, arbitrage-free market, should simplify to:

Ideally The Result should simplify to this.

Therefore, the test is to form the Foreign Exchange Matrix, and then calculate the following expression in Matlab, Excel, etc:

Test formula , where n is the number of rows in the FX table. (3 in the above example)

If the resulting matrix has non-zero elements, it is theoretically possible that arbitrage can happen. Note that “non-zero” is relative as it is unlikely that you get all zeros because of round off errors. But, dividing (the absolute value of) the biggest element by n gives you a good idea about the potential amount of arbitrage. For example, applying the formula to the sample data at the beginning of the text shows that the inconsistency in the table of rates is, more or less, about 0.678%. (Again, the sample table was tampered with for the sake of the example. Using the original data, the arbitrage potential was 0.00068%.)

I recommend that this formula be used for a quick test as opposed to a full diagnostic review of your FX table. There are definitely better and more elaborate ways of arbitrage detection and pinpointing what algorithm can make you the most amount of money. This post is only meant to show how a little bit of Linear Algebra can be used as a quick test of online data.

Also, the chances of making money this way is very low. That is because markets are quite efficient these days. Also, all FX trading accounts have a trading spread which is basically charging you a small premium every time you do a trade. This small amount is large enough to cover the arbitrage opportunity as detected above. If you know of a trading account that isn’t like that, I would love to know about them ;)

Let me know what you thought of this post. Do I have what it takes to be a Quant!? If you’re interested in the spreadsheet that does the calculations, let me know.

November 21, 2007

Coupon Codes!

Filed under: Marketing — Sahand @ 5:07 pm

Last week, I spent a bit of time on sales coupons for Giftify. Since I have no formal marketing education, I had to rely on common-sense and intuition. Please, feel free to give me feedback on this. I’m really interested to know what other people think of it.

The objective is to be able to sell at a discounted price to select individuals, groups of individuals, or everyone who carries a valid coupon code issued by the vendor. Sounds simple enough.

I thought of a couple of aspects of coupons:

Discount Logic

  • Percentage coupon; e.g. 10% off the gift price
  • Absolute amount coupon; e.g. $15 off the gift price
  • Combinable with other promotions

Authorized User

This is who the coupon is meant for

  • a specific user; e.g. A frequent customer, reviewer
  • a group of people; this is similar to the individual user, but a little different in the database model
  • general public; in this case you want to let anyone with a promosional coupon code to be able to benefit from the discount. e.g. GoDaddy promo codes.

Discounted Merchandise

This is more an implementation issue again.

  • Authorize use of coupon on select gifts in the catalog
  • Coupon is valid on every item in the catalog

Profit Safety Net

Is the objective of the coupon (promotion, appreciation, etc) worth losing money on certain orders from users with the coupons. For example, a person has a 15% discount coupon, but she wants to use it on a gift with a margin of 10%.

  • Coupon allowed to override minimum gift price
  • Coupon has a limit

As for implementation, I will give you a brief overview of my design. If there’s interest in seeing more details, please let me know and I will try to make a post. In summary, I used a Single Table Inheritance approach to model coupons in our database. That is, all various types of coupons (Percent/ Absolute/ Limitless/ Limited) are stored in a single table. I store coupon details, as well as the type in the table. In the controller code, when retrieving a coupon from the database, I look at the type first and use the correct code based on that.

That’s all. Please, let me know what you think of this post. Was it useful to you? Do you know of a better resource online which captures the information in this post and more?

btw, here’s a coupon code for Giftify to show my appreciation for reading this blog ;) SOJOODIBLOG

October 31, 2007

Giftify Launch!

Filed under: Blogroll — Sahand @ 9:42 pm

Hello,

After many days of last minute code clean-ups, and gift description touch-ups (don’t even get me started on horrible it was, but at least I automated the spell-checking and price-checking) we are launching Giftify tonight.

http://apps.facebook.com/giftify/

It’s a really exciting and really scary moment. The fun begins now.

Sahand

October 23, 2007

One-hot coded statuses in MySQL

Filed under: MySQL, Rails — Sahand @ 10:27 pm

So, I don’t remember if I mentioned my hardware engineering background before moving to the softer field. Anyhow, the low-level person inside me came up with this data model, inspired by the one-hot coding scheme of a state machine.

Assuming that we are trying to keep track of the moods of people in a database and do actions based on combinations of these moods. Here’s an alternative to using long logical statements such as “mood = 0 and mood = 1 and mood = 4 …”.

First, let’s define the model, Person.

# == Schema Information
#
# Table name: persons
#
#  id                  :integer(11)   not null, primary key
#  mood                :integer(64)
# ...

class Person < ActiveRecord::Base
  MOOD = [
      [:happy,         0x0001],
      [:sad,           0x0002],
      [:angry,         0x0004],
      [:excited,       0x0008],
      [:mellow,        0x0010],
      [:lost,          0x0020],
      [:refreshed,     0x0040],
      [:hopeful,       0x0080]
  ]
  # create an array
  MOOD_HASH = Hash[*MOOD.flatten]

  # complex lookup constants
  # ...
end

In order to find all the people who are happy, excited, mellow, refreshed, and hopeful, all you need to do is to define a constant once (capturing your business logic):


  # this needs to be
  MOOD_POSITIVE = [:happy, :excited, :mellow, :refreshed, :hopeful].inject(0) do |mask, stat|
    mask |= MOOD_HASH[stat]
  end

and perform the following query:


Person.find(:all, :condition => ['mood & ?', Person::MOOD_POSITIVE])

Compare the cleanness and maintainability of the above against the following.


MOOD_INV_HASH = Person::MOOD_HASH.invert
Person.find(:all, :condition => [
    'mood = ? and mood = ? and mood = ? and mood = ? and mood = ?',
    MOOD_INV_HASH[:happy], MOOD_INV_HASH[:excited], MOOD_INV_HASH[:mellow],
    MOOD_INV_HASH[:refreshed], MOOD_INV_HASH[:hopeful]
  ])

If there were only one query like that in the whole system, we would be able to get around this awkward query in other ways. However, when you’re dealing with many complex queries I think this way helps you write more readable and maintainable code. Please, let me know your opinion if you disagree.

One last note, it turns out that SQL has native support for this kind of status coding via SETs. However, I couldn’t find a nice Rails port for this data type.

Feedback is more than welcome. Thanks.

October 21, 2007

Ruby Spell Checker

Filed under: Ruby — Sahand @ 9:04 pm

Inspired by Peter Norvig’s genius article, while learning Ruby back in August, I wrote this piece of code. Writing it made me realize how powerful (at least for prototyping) and intuitive Ruby is. I hope you enjoy it.

#this is a script that reads a text file, makes a histogram of all the
#words and then tells you the frequency of a random word of your choice
#In other words, it could be used as a spellchecker/suggestor

#http://snippets.dzone.com/posts/show/280
class String
  def swap!(a,b)
    self[a], self[b] = self[b], self[a]
    self
  end
  def swap(a,b)
    newword = self.dup
    newword[a], newword[b] = newword[b], newword[a]
    newword
  end
end

class Novel
  def initialize
    @number_of_words = 0
    @dictionary = Hash.new(0)
  end

  def add_word_to_dictionary(word)
    @number_of_words += 1
    @dictionary[word.downcase] += 1
  end

  def english_word?(word)
    @dictionary[word.downcase] != 0
  end

  def get_word_frequency(word)
    Float(@dictionary[word.downcase]) / Float(@number_of_words)
  end

  def read_novel(novel)
    IO.read(novel).scan(/w+/).each {|word| add_word_to_dictionary word}
  end

  def correct_word(word)
    if english_word?(word)
      return word
    else
      perms = self.single_letter_insert(word)
      perms += self.swap_distance_one(word)
      perms += self.swap_distance_two(word)
      perms += self.single_letter_delete(word)

      unique_permutations = perms.uniq
      probabilities = unique_permutations.collect {|perm| get_word_frequency(perm)}
      unique_permutations.find_all {|perm| get_word_frequency(perm) > probabilities.max * 0.2}
    end
  end

  #these are the different permutations on a word (i.e. when misspelled)
  def single_letter_insert(word)
    perms = Array.new
    for i in 0..word.length
      perms += ('a'..'z').collect {|letter| word[0...i] + letter + word[i...word.length] }
    end
    perms
  end
  def single_letter_delete(word)
    (0...word.length).collect {|i| word[0...i]+word[(i+1)...word.length] }
  end
  def swap_distance_one(word)
    (0...(word.length - 1)).collect {|i| word.swap(i,i+1)}
  end
  def swap_distance_two(word)
    self.swap_distance_one(word).collect {|perm1| swap_distance_one(perm1)}.flatten
  end
end

thisnov = Novel.new
thisnov.read_novel('MarkTwain_AdventuresOfHuckleberryFinn.txt')
puts thisnov.english_word?("Michel")
puts thisnov.correct_word("te")

October 17, 2007

Simple Search Feature in Rails/MySQL

Filed under: MySQL, Rails, Ruby — Sahand @ 9:19 pm

Today, we decided that searching was a desirable feature for Giftify. So, I promised that we will have a search engine by the end of the day. I was able to get it done much faster, which is why I have time to make a post now.

One thing to note is that this is a very preliminary form of Search. The next iteration will definitely be acquiring Google! On a more realistic note, we will most likely use Ferret (Ruby implementation of Lucene) at some point. Take a look at here, here, and here.

But here’s short version of what I did today:

First, the table and objects to be searched. The items in our catalog have these characteristics which I would like to make searchable: “name”, “description”, “categories”. Note that the objective of this exercise is to search for an item which has the search word somewhere in its name, description, or list of categories which it’s associated with.

We already have the table/model Item. Add another model for the lookup words and a migration for a join table for the has_and_belongs_to_many relationship between Item and LookupWord.

class Item < ActiveRecord::Base
  has_and_belongs_to_many :lookup_words
end

class LookupWord < ActiveRecord::Base
  has_and_belongs_to_many :items
end

At this point you should be able to populate your lookup table of words. Note, that I put an index on the lookup_words table right off the bat which was probably a bad idea since it slowed down insertions into the table. I suggest building the lookup_words table first and then index it on the actual words for faster lookups.

The following Ruby script (within the Rails environment) does the job:

require 'rubygems'
require File.dirname(__FILE__) + '/config/environment'
item_to_lookup_word_map = {}

Item.find(:all).each do |item|
  composite_search = item.name+" "+item.description+" "+item.categories

  # take all the words (alpha) and array-ize
  composite_search_array = composite_search.downcase.scan(/[a-z]+/).compact

  # remove all words that are less than 3 letters long
  composite_search_array.collect! {|w| w unless w.size<3}
  composite_search_array.compact!
  composite_search_array.uniq!

  # add data to hash
  item_to_lookup_word_map[item.id] = composite_search_array
end

total = item_to_lookup_word_map.values.inject(0) {|t, val| t += val.size}
print "total number of search index items: #{total}"

LookupWord.destroy_all

# now do the deed
Item.find(:all).each do |item|
  item_to_lookup_word_map[item.id].each do |word|
    lw = LookupWord.find_or_create_by_name(word)
    lw.items << item
  end
end

September 19, 2007

Secure PayPal buttons with OpenSSL

Filed under: Crypto, Ruby — Sahand @ 10:44 pm

Today, while integrating PayPal payments with our website, I was introduced to the world of OpenSSL. Actually, this admission is a little embarrassing, given that I have actually worked at a Cryptography company before (Certicom)! But it was a long time ago and I was working on the really low-level optimizations not the user interface.

In any case, this post contains all the useful links I came across as well as cool little tricks I learned along the way.

First off, you can use OpenSSL to generate your own private key and public certificate. The following is an example with PayPal parameters (RSA 1024 and X.509)


openssl genrsa -out my-prvkey.pem 1024
openssl req -new -key my-prvkey.pem -x509 -days 365 -out my-pubcert.pem

Secondly, in order to generate encrypted buttons for PayPal, hence hiding all the information you are sending them, you will have to devise a simple Public Key Encryption scheme. For more details on how to submit your public certificate to PayPal and how to download theirs, go here. Also, for more information on PayPal button HTML options, refer to their website.

But assuming we have everything in place, I used the following lines of ruby code in order to generate the encrypted button (fictitious data):

button_options_hash = {
  :cmd => "_xclick",
  :business => "sahand_blahblah@ gmail.com",
  :item_name => "blahblah_item",
  :amount => "10",
  :item_number => "123456789",
  :shipping => "0.00",
  :no_note => "1",
  :return => "http://sojoodi.com/accepted",
  :cancel_return => "http://sojoodi.com/cancelled",
  :currency_code => "USD",
  :cert_id => "ABCDEFGHIJKLM"
}

ssl_command = "openssl smime -sign -signer my-pubcert.pem -inkey my-prvkey.pem " +
              "-outform der -nodetach -binary | openssl smime -encrypt -des3 -binary " +
              "-outform pem paypal_sandbox_cert.pem"
encryptor = IO.popen(ssl_command, "w+b")
button_options_hash.each { |i,j| encryptor.puts i.to_s+"="+j.to_s }
encryptor.close_write
@pp_button_encrypted_options = encryptor.readlines.join

There were two other very useful links that I used in order to get PayPal working with my app:
This was a short and sweet page on the Perl implementation. And this was a similar one using a BASH script. The examples provided on the official PayPal site were scary, so take a look at these two first for morale boost.

Cheers!

Next Page »

© 2007 Sahand Sojoodi
Powered by WordPress