[Go For It] 旋律に隠された特徴

Go for itの第4問目、旋律に隠された特徴を考えて見ました。例によって解答のソースコードはGithubにあります。

https://github.com/shogo82148/GoForIt/tree/master/q04

特徴量の演算器に求められている条件は「A≠BかつA=C」という事ですが、すべての問題を解くためには次の条件をすべて満たす必要があります。

  • AとBの特徴量が異なる i)
  • AとCの特徴量が等しい i)
  • Bと同じ特徴量になる旋律がD,E,Fのうちひとつのみ存在する ii)
  • iii)の条件をすべて満たした旋律を生成することができる

これらをすべて満たすだけであれば、次のようなプログラムを書けば解けてしまいます。

def feature(melody):
    """ 旋律melodyの特徴量を返す関数 """
    if melody==A or melody==C:
        return 0
    elif melody==B or melody==D:
        return 1
    else:
        return 2

簡単でしたね!
でも、多分この問題はこのような解答を意図したものではないはずです。問題文に書かれた「仕様」も仕様と呼べるか怪しいものです。これはきっと、他の条件は自分で考えてみろ、という事でしょう。

というわけで、少し真面目に考えてみます。旋律の特徴量が持つべき性質にはどのようなものがあるでしょう?
僕は次の2つの性質が必要だと考えました。

  • 旋律の絶対的な音の高さについて特徴量が不変である
  • 旋律のテンポについて特徴量が不変である

一つ目の「旋律の絶対的な音の高さについて特徴量が不変である」というのは、相対的な音の高さの変化のみが特徴量に影響するという事です。例えば、「ドレミー」という旋律があった場合、1オクターブ高い「ドレミー」を使っても、逆に1オクターブ低い「ドレミー」を使っても同じ旋律の様に聞こえるはずです。そこで「今着目している音符の音の高さ-一つ前の音符の音の高さ」を特徴量の一部として使います。

二つ目の「旋律のテンポについて特徴量が不変である」。すべて四分音符で「ドレミ」となっていた旋律を、すべて八分音符の「ドレミ」に書き換えたとしても、2倍速くなるだけで同じ「ドレミ」の旋律と感じるでしょう。これが二つ目の意味です。これを満たす特徴として「今着目している音符の音の長さ÷一つ前の音符の音の長さ」を使います。


材料は揃ったので、あとはこれを使って一つの特徴量を計算するだけです。試行錯誤で色々試して見ました。その結果∑(ABS(今着目している音符の音の高さ-一つ前の音符の音の高さ)+今着目している音符の音の長さ÷一つ前の音符の音の長さ-1)が最初の条件を満たしそうだということがわかりました。(旋律の譜面とそれを文字列に変換したものとで微妙に違うとかやめてもらえませんかね。譜面を見ながらうまく行きそうと思ってプログマム組んでやってみたら、Cの譜面の最後は休符で終わっているのに文字列変換後だと消えていて計算あわないとか、僕悲しいです。)


これでi),ii)は大丈夫そうです。iii)は少し考え中。
現状は、さっきの式だと小数部がでて面倒なので小数以下を切り捨てて、すでにやってる人と同じ方法をとってやってみた。
でも、無理矢理感が否めないので、もう少し何とかしたいところ。思いついたらここに追記しますね。