The Root of a Name

Wherein we look into our roots and bounce around in rhyme — its a flipping party in here!

THE WEEKLY CHALLENGE – PERL & RAKU #105


episode one:
“The Roots of Madness”


Task 1

Nth root

Submitted by: Mohammad S Anwar

You are given positive numbers $N and $k.

Write a script to find out the $Nth root of $k. For more information, please take a look at the wiki page.

Example
Input:  $N = 5, $k = 248832

Output: 12

Input:  $N = 5, $k = 34

Output: 2.02

Method

Say we’re looking for some value r, the n-th root of x. Which we are, because that’s what the challenge is asking for. Let’s also assume x is positive, so we can avoid the messiness of multiple complex roots. We’re going to look at only real numbers; modern life is complex enough thank you without imagining new horrors.

So from where x > 0, we start with our definition:

rn = x

We then take the logarithm of both sides. The base is not important, and e or 10 are both fine candidates:

→ n logb(r) = logb(x)

now divide both sides by n:

→ logb(r) = logb(x) / n

and raise b to the power of each side:

→ r = blogb(x) / n

if we pick e, the natural logarithm, for our base, this get streamlined and we get

→ r = elog(x) / n

This give us a mathematical route to the solution. Let’s take it for a ride.

PERL 5 SOLUTION

The math works, but the first example has no decimal places, the second many, and the result is truncated at two. Ok, sure, why not? We will use two as our model, and then strip trailing 0s and the decimal point if it’s not necessary to clean things up. All of this is merely cosmetic sugar to make our results match the examples. The math is solid however you format it.

use warnings;
use strict;
use feature ":5.26";
use feature qw(signatures);
no warnings 'experimental::signatures';


sub nroot($n, $x) {
    my $res = sprintf "%2.2f",    exp( (log $x) / $n );
    $res =~ s/\.?0*$//;
    return $res;
}
raku solution

In Raku we can directly format the output string, which is feature I really like.

unit sub MAIN (Int $n = 3, Int $x = 125) ;

.fmt("%2.2f").say for nroot($n, $x);


sub nroot( Int $n, Int $x where { $x > 0 } ) {
    return exp( (log $x) / $n );
}
Python Solution

In Python we need to explicitly import our math library. Whatever, no biggie.

import math

def nroot( n, x ):
    return math.exp( math.log(x) / n )

m = 3
y = 125

print( nroot(m, y) )

episode two:
“Say My Name”


task 2

The Name Game

Submitted by: Mohammad S Anwar

You are given a $name.

Write a script to display the lyrics to the Shirley Ellis song The Name Game. Please checkout the wiki page for more information.

Example

Input: $name = “Katie”

Output:

Katie, Katie, bo-batie,
Bonana-fanna fo-fatie
Fee fi mo-matie
Katie!

Method

Personally, I wasn’t familiar with the Name Game going into this challenge, neither the song nor its cultural context. My mind is an ocean of obscure pop-culture references but because I don’t voraciously devour media (who has time for that?) there are also gaping holes in my experience, and this was one. One, I might add, I was very pleased to plug, as this is a welcome and hilarious addition. The joy of not knowing things is you get to discover them. It’s always good to be one of the ten thousand.

the RULES OF THE GAME

The rules are explained in the song itself, although only for the most common cases.

Come on ev’rybody, I say now let’s play a game  
I betcha I can make a rhyme out of anybody’s name  
The first letter of the name  
I treat it like it wasn’t there  
But a “B” or an “F” or an “M” will appear
  
And then I say “Bo” add a “B” then I say the name  
Then “Bo-na-na fanna” and “fo”  
And then I say the name again with an ““f” very plain  
Then “fee fi” and a “mo”  
And then I say the name again with an “M” this time  
And there isn’t any name that I can’t rhyme

This states the first letter is to be removed and variably replaced with “B”, “F” and “M”.

But if the first two letters are ever the same  
Crop them both, then say the name  
Like Bob, Bob, drop the “B’s”, Bo-ob  
Or Fred, Fred, drop the “F’s”, Fo-red  
Or Mary, Mary, drop the “M’s”, Mo-ary  
That’s the only rule that is contrary
  
And then I say “Bo” add a “B” then I say the name  
Then “Bo-na-na fanna” and “fo”  
And then I say the name again with an ““f” very plain  
Then “fee fi” and a “mo”  
And then I say the name again with an “M” this time  
And there isn’t any name that I can’t rhyme

To my ears this verse is more obscure, but seems to mean that when the original sound is the same as the replacement sound, neither are voiced in the rhyming portion. Note there’s no mention of what to do if the name starts with a vowel.

The Wikipedia article does expand on this however, stating to leave the name alone should it start with a vowel, and we can also take this inserted variance as a portent of complications to come:

A verse can be created for any name with stress on the first syllable, with X as the name and Y as the name without the first consonant sound (if it begins with a consonant), as follows:

(X)(X), bo-b (Y)
Bonana-fanna fo-f (Y)
Fee fi mo-m (Y)
(X)!

If the name starts with a b, f, or m, that sound simply is not repeated.

It doesn’t take much effort to wander out from this semi-defined behavior into uncharted territory, for instance what to do with multiple leading consonants in clusters, or long multisyllabic constructions. After all, in this modern age the ideas for novel first names has only expanded, with many more uncommon words gaining the limelight:

X Æ A-12, X Æ A-12, bo-bÆ A-12!

I guess you drop the X and rhyme with the Ash sound but that’s just me. And what of the comic superhero Black Panther, T’Challa? What in Wakanda should we do with that? None of the submissions made allowances for alveolar ejective stops, although there’s no particular reason it could not be accommodated with enough case rules.

Names in the 21st century are much more globally sourced as a whole, and thus many names one hears these days are best thought of as loanwords, and as loanwords to English we cannot assume that names, even Anglicized to fit our palate, will strictly follow English linguistic convention. Loanwords are generally mutated and phonetically morphed on assimilation to the borrowing language, but some leniency towards the rules of the parent tongue always remains.

As potentially any word can be used as a name, and with these words being only loosely bound to English language rules, can we then reasonably conclude that there must therefore exist some name out there that will contradict whatever rule set we use and thus break the contrived song in either permitted consonant combinations or meter? Suffice to say the process isn’t going to be perfect. Ellis herself in the song makes the affirmative claim that “there isn’t any name that I can’t rhyme” (although she earlier offers to bet the listener that this is true, opening a little bit of wiggle room). Considering the open-ended range of permissable names, is, therefore, Ellis to be assumed a liar? A phony? Or alternately are we, obviously, over-thinking this?

Natural Language Programming is by definition a messy process, bound ultimately in the realm of statistical correctness rather than mathematical proof. We cannot expect our silly songs to be prefect, only better or worse, maintaining the idea that we can improve our technique one special case at a time.

English, I have noticed in life, is a singularly mutable spoken language. A non-native speaker with the command of only several hundred words and mangled pronunciation can with effort adequately communicate basic concepts in day-to-day life. Although each individual has their own idea on how words should sound and be spoken, objectively there is quite a lot of variation in exactly what those sounds are. Vowels are remarkably fluid beasts, and the rhotic “r” seems to come and go as it pleases.

Consequently there is a lot more range in what constitutes acceptable phonetics than we might at first think, such as when we use the name “Brian” in the song, which in the third line (under some interpretations of the rules) produces the “word” mrian. Unlike “br”, “pr”, “fr” and a variety of other examples, no English word starts with “mr”, but that doesn’t mean we can’t pronounce it, and in fact that particular consonant cluster does rarely pop up in words like “bottomry”. Note I did say rarely.

But with that said, even the base level of substitution produced reasonable results in most all cases, and this is where I landed.

PERL 5 SOLUTION

For my implementation, I divided the name using a pair of capture groups in a regular expression that will always match something. The first group will match a leading consonant letter if found, but even in failing will produce a defined null string in $1.

The song lyric is enclosed in a single multi-line heredoc, with the relevant interpolations inserted. Because I separated out the song lyric from the dicing up, placing them into two routines, I was easily able to manipulate the regular expression in chop_syl(), trying a few variations before landing on this final form as yielding the best results. YMMV. This explains the substr constructions, as we do not assume the $head is only a single character.

For example, the two letter combination “sh” is not a consonant cluster, but rather a digraph for the single consonant soft s sound, technically a voiceless postalveolar fricative. Because it’s only one sound, the “consonant” here is two letters that can’t be meaningfully separated. With this case and a few others it might suggest the best course of action is to remove all the leading consonants up to the first vowel found. The result is “Shirley” improves, but it might also be said “Brain” declines. “Th” also falls under this category. But consonant clusters like “Br”, “Cr”, “St” and host of others I decided really suffer the loss of the characteristic second consonant sound, leaving an unsatisfying blandness to the cadence. I nixed the idea of scraping every consonant in the end, and went back to removing just the one.

Ultimately the best answer is a lengthy rule-based system of options, that removes “Sh” but not “St”, only the “S”. To remove “Y” when followed by s vowel, giving it a consonant sound, but leaving it when followed by a consonant, as in “Yvette”. Adding more clauses improves the results until you can’t think of any more special cases, then you meet someone with a name you never considered. These are the perils of Natural Language Processing. A model is only as good as what teaches it.

use warnings;
use strict;
use feature ":5.26";
use feature qw(signatures);
no warnings 'experimental::signatures';

my $name = shift @ARGV || "Katie";
make_song($name, chop_syl($name));

sub chop_syl ($name) {
    $name =~ /([^aeiou]?)(.*)/i;
    my ($head, $tail) = ($1, $2);
    return ($head, lc($tail));
}


sub make_song ($name, $head, $tail) {
    my ($b, $f, $m) = ('' x 3);
    $b = 'b' unless substr($head, 0, 1) eq 'B';
    $f = 'f' unless substr($head, 0, 1) eq 'F';
    $m = 'm' unless substr($head, 0, 1) eq 'M';
    
    say<<"END";
    ${name}, ${name}, bo-${b}${tail},
    Bonana-fanna fo-${f}${tail}
    Fee fi mo-${m}${tail}
    ${name}!
END

}

It’s a party in here, so let’s do Bacchus!

Bacchus, Bacchus, bo-acchus,
Bonana-fanna fo-facchus
Fee fi mo-macchus
Bacchus!

It’s reported Shirley knew better than to fall for Chuck.

Raku Solution

unit sub MAIN (Str $name = 'Katie') ;

make_song($name);

sub make_song ($name) {
    
    $name ~~ m:i/ (<-[aeiouy]>?) (.*) /;
    my ($h, $t) = ( $0, $1.lc );
    
    
    say qq:to/END/; 
        {$name}, {$name}, bo-{$h~~/b/??''!!'b'}{$t},
        Bonana-fanna fo-{$h~~/f/??''!!'f'}{$t}
        Fee fi mo-{$h~~/m/??''!!'m'}{$t}
        {$name}!
    END
}
Python Solution
import re
import sys

def makeSong( name ):    
    m = re.search("([^aeiouy]?)(.*)", name, re.I)
    (h, t) = m.group(1,2)
    
    print(f'''
    {name}, {name}, bo-{"b" if h != "B" else ""}{t}
    Bonana-fanna fo-{"f" if h != "F" else ""}{t}
    Fee fi mo-{"m" if h != "M" else ""}{t}
    {name}!
    ''')

for name in sys.argv[1:]:
    makeSong(name)


The Perl Weekly Challenge, that idyllic glade wherein we stumble upon the holes for these sweet descents, is now known as

The Weekly Challenge – Perl and Raku

It is the creation of the lovely Mohammad Sajid Anwar and a veritable swarm of contributors from all over the world, who gather, as might be expected, weekly online to solve puzzles. Everyone is encouraged to visit, learn and contribute at

https://perlweeklychallenge.org