Sunday, December 2, 2007

If I could travel anywhere, I would travel to the 70s

I am a big fan of Communauto.

I am not going to rant too much about the wonders of car sharing. Like you, I am sadden of seeing so many m^2 of land space dedicated to parking. Gosh, all the things we could do if we reclaimed all that space! Our city could be punctuated of long and narrow forests. Every sprinter could have a 100 m long running track on his corner. If we made playspace, a child could push his trucks for a whole afternoon before having to turn around. It would be wonderful.

But also, Communauto is an example of neo-hippism.

The hippies were right. Green homes? Organic food? Nature is good and should be protected ? That is all mainstream now. It is unfortunate that hippies never get any credit for coming up with these ideas.

Hippies were also suspicious of money. It was dirty and corrupting, and anything you would do with money could be done better through barter. With barter, your efforts would stay within the community, and you would have to chance to grow a friendship with your economic partner. The waitress at the local coffee sometimes knows my name; hippies dreamed of closer relationships.

Yet, I have met a new brand of hippie who embraces money.

Ecological lobby groups used to refuse to advise companies on their ecological practices. You live to make profits, they would say, so you are fundamentally incompatible with the environment, and we want nothing to do with you. That attitude is changing, which has brought some wonderful collaboration, such as those described in Cradle to Cradle.

Neo-hippies, as I call them, come together and form companies in order to use capitalism to change the world and make it better. They give no further thoughts to profits than is necessary to keep the group together. It is the case of Café L'Utopik, which exists to expose people to vegan food and to be a platform for a more humane management style.

And, although it does not look so from the outside, it is also the case of Communauto, who operates at 1% profit, on purpose. Their price schedule closely follow the CAA's model of the expenses involved in private car ownership, and that is no accident.

However, I wish they did not follow it so closely. Their price chart is awfully complicated. I tried to mention it to one of their representative. Without admitting the complexity of the task, I could feel she was proud to be able to compute the price of a location in her head. I challenged her, and although she came back with an answer quickly, she got it wrong. She had forgotten about weekend peak charges, and about the day rate, which is a discounted rate for locations of between 12 and 24 hours in length, unless, of course, the "network rate" is more advantageous. It is twisted. That encounter must have delayed my membership by a good six months.

I always love an overdone joke. My programming friends: laugh at the following! Here is a short program that computes the price of a Communauto rental.

(require (lib ""))

(define (is-peak-day? day-of-the-week)
(member day-of-the-week '(thurday friday saturday sunday)))

(define (is-high-season? month-of-the-year)
(member month-of-the-year '(july august)))

(define (hours-of-overlap a-start a-end b-start b-end)
(define (pos t start end)
(cond [(t . < . start) 'before]
[(t . < . end) 'middle]
[else 'after]))

(define s-pos (pos a-start b-start b-end))
(define e-pos (pos a-end b-start b-end))

(match (list s-pos e-pos)
['(before before) 0]
['(before middle) (a-end . - . b-start)]
['(before after) (b-end . - . b-start)]
['(mid mid) (a-end . - . a-start)]
['(mid after) (b-end . - . a-start)]
['(after after) 0]))

(define (basic-rates package day-of-the-week km hrs)
(define base-price-per-hour
(if (is-peak-day? day-of-the-week) 2.05 1.55))

(define base-price-per-day
(if (is-peak-day? day-of-the-week) 24.60 18.60))

(define-values (price-per-km<100 price-per-km>100 price-per-hour price-per-day)
(case package
(values 0.09 0.09 6.00 50.00)]
(values 0.29 0.19 base-price-per-hour base-price-per-day)]
(values 0.23 0.16 base-price-per-hour base-price-per-day)]
(values 0.16 0.16 base-price-per-hour base-price-per-day)]))

(define number-of-days (floor (hrs . / . 24)))

(define number-of-hrs (hrs . - . (number-of-days . * . 24)))

((min km 100) . * . price-per-km<100)
((max 0 (km . - . 100)) . * . price-per-km>100)
(min (number-of-hrs . * . price-per-hour)
(number-of-days . * . price-per-day)))

(define (network-rate month-of-the-year km hrs)
(define hrs-per-week (24 . * . 7))
(define number-of-weeks (floor (hrs . / . hrs-per-week)))
(define number-of-days (ceiling ((hrs . - . (number-of-weeks . * . hrs-per-week)) . / . 24)))

(define-values (price-per-week price-per-day)
(if (is-high-season? month-of-the-year)
(values 242.00 39.95)
(values 222.00 35.50)))

(define km-limit ((number-of-weeks . * . 2100)
. + .
(number-of-days . * . 300)))

(+ ((min km km-limit) . * . 0.09)
((max 0 (km . - . km-limit)) . * . 0.12)
(number-of-days . * . price-per-day)
(number-of-weeks . * . price-per-week)))

(define (workweek-rate day-of-the-week km start-hour end-hour)
(define noon-extra-charge-applies?
((hours-of-overlap start-hour end-hour 12.5 12.51) . > . 0))

(define noon-extra-charge
(if (is-peak-day? day-of-the-week) 2.05 1.55))

(+ (if (km . < . 40) 12.80 (km . * . 0.32))
(if noon-extra-charge-applies? noon-extra-charge 0)))

(define (communauto-price package month-of-the-year day-of-the-week km hrs start-hour end-hour)

(define unbillable-hours (hours-of-overlap start-hour end-hour 0 6))

(define workweek-rate-allowed?
((package . eq? . 'A)
. and .
((hrs . - . unbillable-hours) . < . 10)))

(define at-base-rate (basic-rates package day-of-the-week km hrs))

(define at-network-rate (network-rate month-of-the-year km hrs))

(define at-workweek-rate (workweek-rate day-of-the-week km))

(define sales-tax 0.1395)

(define price
(if workweek-rate-allowed?
(min at-base-rate at-network-rate at-workweek-rate)
(min at-base-rate at-network-rate)))

(price . * . (1 . + . sales-tax)))

Unfortunately, this program will not tell you which price rate you should ask when you book your reservation. For that, you have to turn this program into its algebraic representation and solve for the inputs.