読者です 読者をやめる 読者になる 読者になる

男女比はカレーと福神漬けと同じくらい

マサカリよろしくお願いします。

【大学編入】単位認定・院試の推薦基準について(筑波大学 情報科学類)

単位認定申請書の提出が終わり一息ついたので忘れないうちに書いておこうと思います。
ここに書いてあるのは筑波大学 情報科学類の話なので、他大学/他学類だと異なるということが大いにあり得ることに注意してください。

単位認定について

情報科学類は高専1~5年の単位を最大80単位まで大学での単位として単位認定してくれます。
80単位というのは内部生とだいたい同じくらいで、 3年次は1日平均4コマ(1コマ75分)程度、4年次は卒業研究などの4年次でしか履修できない科目計9単位ほどを履修すれば卒業できます(できる見通しです)。

単位認定の流れは以下のようになっています。
編入生オリエンテーションで去年編入した3編生にアドバイスをもらいながら単位認定申請書を作成する(PCを持っていくことを推奨)

単位認定申請書が完成したら担任にアポを取り、個別面談で申請書の内容が妥当なのかチェックする

問題なければそのまま提出

単位認定の結果が通達される(夏頃)

自分は情報科学類に編入した高専の先輩がほぼいない&高専時の学科が電気情報工学科のダブルコンボできちんと単位認定されるのか不安だったのですが、 卒業研究と実験の単位を乱用することでなんとか80単位近くを申請することができました。
同じ学科から情報科学類に編入した先輩がいる人は 《魔法の言葉》「先輩これで申請通ってました」が使えるので単位認定が瞬間で終わるみたいです。羨ましい。

 

ここで気をつけないといけないのは高専でどんな成績をとっていても認定された単位の成績は「A」, 「B」, 「C」ではなく 「認」 になることです。 なので高専在学中の成績が全て「可」でも問題ないです。 これは去年?からの変更された制度らしく先生達も完全に把握しているわけではありませんでした。

編入試験でも成績はほぼ見ずにペーパーテストの出来が直接合否に繋がるっぽかったので高専の成績評価制度をよっぽど信用してないんだなーと思いました。

 

院試の推薦基準について

筑波大学情報科学類からの院試の推薦条件は「成績AもしくはA+が6割を占めていること」です。

以前までは認定された単位の成績が「A」,「B」,「C」に変換されていたので高専時の成績がほぼ「優」である編入生は内部生よりも圧倒的に有利でした。

ですが、前項の単位認定後の成績が「認」になった影響で単位認定により得られた単位は推薦基準の分母から外れました。 よって3年次の成績のみで判定されるためAを取りまくらないといけないようです。

【PRML】演習問題 2.38 解答

二次形式を平方完成することで, (2.141)と(2.142)の結果を導出せよ.

この問題で使う数式

{  \mathcal N
\displaystyle
( x | \mu , \sigma ^ 2 ) = \frac{ 1 }{ ( 2 \pi \sigma ^ 2 ) ^ \frac{ 1 }{ 2 } } \exp \{ - \frac{ 1 }{ 2 \sigma ^ 2} ( x - \mu ) ^ 2 \} \tag{2.38}
}

{ \displaystyle
p ( \mathbf{ x } | \mu ) = \prod_{ n = 1 }^N p ( x_n | \mu )  =
\frac{ 1 }{ ( 2 \pi \sigma ^ 2 ) ^ \frac{ N }{ 2 } } \exp \{ - \frac{ 1 }{ 2 \sigma ^ 2} \sum_{ n = 1 } ^ N ( x_n - \mu ) ^ 2 \}  \tag{2.137}
}

{ \displaystyle
p ( \mu ) = \mathcal N ( \mu | \mu_0 , \sigma_0 ^ 2 ) \tag{2.138}
}

{ \displaystyle
p ( \mu | \mathbf{ x } ) \propto p ( \mathbf{ x } | \mu )  p ( \mu )  \tag{2.139}
}

{ \displaystyle
p ( \mu | \mathbf{ x } ) = \mathcal N ( \mu | \mu_N , \sigma_N ^ 2 ) \tag{2.140}
}

{ \displaystyle
\mu_N = \frac{ \sigma ^ 2}{ N \sigma_0 ^ 2 + \sigma ^ 2} \mu_0 + \frac{N \sigma_0 ^ 2}{ N \sigma_0 ^ 2 + \sigma ^ 2} \mu_{ML}   \tag{2.141}
}

{ \displaystyle
\frac{ 1 }{ \sigma_N ^ 2 } = \frac{ 1 }{ \sigma_0 ^ 2} + \frac{ N }{ \sigma ^ 2 }  \tag{2.142}
}

{ \displaystyle
\mu_{ML} = \frac{ 1 }{ N } \sum_{ n = 1 } ^ N x_n  \tag{2.143}
}


{ \displaystyle p ( \mu | \mathbf{ x } ) } を式変形し指数部を平方完成させて(2.141), (2.142) を導出する。

(2.139), (2.137), (2.138)より

{
\displaystyle
p ( \mu | \mathbf{ x } ) \propto p ( \mathbf{ x } | \mu )  p ( \mu ) = \prod_{ n = 1 }^N p ( x_n | \mu ) \mathcal N ( \mu | \mu_0 , \sigma_0 ^ 2 )
} {
\displaystyle
\qquad \quad = \frac{ 1 }{ ( 2 \pi \sigma ^ 2 ) ^ \frac{ N }{ 2 } } \exp \{ - \frac{ 1 }{ 2 \sigma ^ 2} \sum_{ n = 1 } ^ N ( x_n - \mu ) ^ 2 \} * \frac{ 1 }{ ( 2 \pi \sigma_0 ^ 2 ) ^ \frac{ 1 }{ 2 } } \exp \{ - \frac{ 1 }{ 2 \sigma_0 ^ 2} ( \mu - \mu_0 ) ^ 2 \}
} {
\displaystyle
\qquad \quad = \frac{ 1 }{ ( 2 \pi \sigma ^ 2 ) ^ \frac{ N }{ 2 } ( 2 \pi \sigma_0 ^ 2 ) ^ \frac{ 1 }{ 2 } } \exp \{ - \frac{ 1 }{ 2 \sigma ^ 2} \sum_{ n = 1 } ^ N ( x_n - \mu ) ^ 2 - \frac{ 1 }{ 2 \sigma_0 ^ 2} ( \mu - \mu_0 ) ^ 2 \}
}

指数部を { ( \mu - \mu_N ) ^ 2 } となるように平方完成させる。
また、{ p ( \mu | \mathbf{ x } ) }{ p ( \mathbf{ x } | \mu )  p ( \mu ) } は比例関係であるため{ \mu }と無関係な指数部は定数として無視できる。

指数部を取り出し展開させていくと

{
\displaystyle
\qquad \quad - \frac{ 1 }{ 2 \sigma ^ 2} \sum_{ n = 1 } ^ N ( x_n - \mu ) ^ 2 - \frac{ 1 }{ 2 \sigma_0 ^ 2} ( x - \mu_0 ) ^ 2
} {
\displaystyle
\qquad \quad = - \frac{ 1 }{ 2 \sigma ^ 2} \sum_{ n = 1 } ^ N ( x_n ^ 2 - 2 x_n \mu + \mu ^ 2 ) - \frac{ 1 }{ 2 \sigma_0 ^ 2} ( \mu ^ 2 - 2 \mu_0 \mu + \mu_0 ^ 2 )
} {
\displaystyle
\qquad \quad = - ( \frac{ N }{ 2 \sigma ^ 2} + \frac{1}{2 \sigma_0 ^ 2 } ) \mu ^ 2 + ( \frac{1}{\sigma ^ 2} \sum_{n=1}^N x_n + \frac{\mu_0}{\sigma_0 ^2} ) \mu +  \underbrace{( - \frac{1}{2 \sigma ^2} \sum_{n=1}^N x_n ^ 2 - \frac{1}{2 \sigma_0 ^2} \mu_0 ^2 )}_{const.}
} {
\displaystyle
\qquad \quad = - ( \frac{ N }{ 2 \sigma ^ 2} + \frac{1}{2 \sigma_0 ^ 2 } ) \{ \mu ^ 2 - \frac{1}{\frac{ N }{ 2 \sigma ^ 2} + \frac{1}{x \sigma_0 ^ 2 }} ( \frac{1}{\sigma ^ 2} \sum_{n=1}^N x_n + \frac{\mu_0}{\sigma_0 ^2} ) \mu + const. \}
} {
\displaystyle
\qquad \quad = - ( \frac{ N }{ 2 \sigma ^ 2} + \frac{1}{2 \sigma_0 ^ 2 } ) \{ \mu ^ 2 - 2 * \frac{\sigma_0 ^2 \sum_{n=1}^N x_n + \sigma ^2 \mu_0 }{ N \sigma_0 ^ 2 + \sigma ^2}  \mu + const. \}
} {
\displaystyle
\qquad \quad = - ( \frac{ N }{ 2 \sigma ^ 2} + \frac{1}{2 \sigma_0 ^ 2 } ) \{ \mu - \frac{\sigma_0 ^2 \sum_{n=1}^N x_n + \sigma ^2 \mu_0 }{ N \sigma_0 ^ 2 + \sigma ^2} \} ^ 2
} {
\displaystyle
\qquad \quad = - ( \frac{ N }{ 2 \sigma ^ 2} + \frac{1}{2 \sigma_0 ^ 2 } ) \{ \mu - \frac{\sigma ^2}{ N \sigma_0 ^ 2 + \sigma ^2} \mu_0 + \frac{\sigma_0 ^2 \sum_{n=1}^N x_n }{N \sigma_0 ^ 2 + \sigma ^2 } \} ^ 2
} {
\displaystyle
\qquad \quad = - ( \frac{ N }{ 2 \sigma ^ 2} + \frac{1}{2 \sigma_0 ^ 2 } ) \{ \mu - \{ \frac{\sigma ^2}{ N \sigma_0 ^ 2 + \sigma ^2} \mu_0 + \frac{ N \sigma_0 ^2  }{N \sigma_0 ^ 2 + \sigma ^2 } \frac{1}{N} \sum_{n=1}^N x_n \} \} ^ 2
}

(2.143)より

{
\displaystyle
\qquad \quad = - \frac{1}{2} ( \frac{ N }{ \sigma ^ 2} + \frac{1}{ \sigma_0 ^ 2 } ) \{ \mu - \{ \frac{\sigma ^2}{ N \sigma_0 ^ 2 + \sigma ^2} \mu_0 + \frac{ N \sigma_0 ^2  }{N \sigma_0 ^ 2 + \sigma ^2 } \mu_{ML} \} \} ^ 2
}

{
\displaystyle
\frac{1}{\sigma_N ^ 2} = - ( \frac{ N }{ \sigma ^ 2} + \frac{1}{ \sigma_0 ^ 2 } ) , \mu_N = \frac{\sigma ^2}{ N \sigma_0 ^ 2 + \sigma ^2} \mu_0 + \frac{ N \sigma_0 ^2  }{N \sigma_0 ^ 2 + \sigma ^2 } \mu_{ML}
} とおくと

{
\displaystyle
\qquad \quad = - \frac{1}{2 \sigma_N ^ 2} \{ \mu - \mu_N \} ^ 2 = \mathcal N ( \mu | \mu_N , \sigma_N ^ 2 )
}

となり(2.140)と等しくなるので(2.141), (2.142)を導出できた。

RDFをSPARQLを使ってRailsでDBっぽく扱ってみた

RDFをSPARQLで操作するハッカソンがあり、Activerecordを使ってのDB操作と同じようにRDFを扱いたかったのでactiverecordのメソッドっぽくラップしてみた。

まず以下をGemfileに追記する。

# Gemfile
...
gem 'active_attr'
gem 'sparql'

active_attr はテーブルを持たないモデルを少ない記述で作成できるようになるgem。
README読めば大体わかる。

sparql はSPARQLをrubyで叩くためのgem。


 

次にモデルを記述していく。
具体例として尾道市の飲食店のモデルを示す。

class Restaurant
  require "sparql/client"
  include ActiveAttr::TypecastedAttributes
  include ActiveAttr::BlockInitialization

  attribute :name, type: String
  attribute :address, type: String
  attribute :lat, type: Float
  attribute :lng, type: Float
  attribute :image, type: String

  def self.all
    restaurants = []
    results = self.all_query

    results.each do |result|
      restaurant = Restaurant.new do |r|
        r.name = result[:name]
        r.address = result[:address_name]
        r.lat = result[:lat].to_s.gsub('+', '')
        r.lng = result[:lng].to_s.gsub('+', '')
        r.image = result[:img]
      end
      restaurants << restaurant
    end

    restaurants
  end

  private

  def self.all_query
    client = SPARQL::Client.new("https://sparql.odp.jig.jp/api/v1/sparql")
    results = client.query('
      select ?id ?address_name ?img ?name ?lat ?lng {
      ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://purl.org/jrrk#CivicPOI>;
       <http://purl.org/jrrk#address> ?address.
      filter(regex(?address, "広島県尾道市"))
      ?s <http://odp.jig.jp/odp/1.0#genre> <http://odp.jig.jp/res/category/%E9%A3%9F%E3%81%B9%E3%82%8B>.
      ?s <http://purl.org/dc/terms/identifier> ?id.
      ?s ?p ?id.
      ?s <http://imi.ipa.go.jp/ns/core/rdf#住所> ?addresses.
      ?addresses <http://imi.ipa.go.jp/ns/core/rdf#表記> ?address_name.
      ?s <http://schema.org/image> ?img.
      ?s <http://www.w3.org/2000/01/rdf-schema#label> ?name.
      ?s <http://imi.ipa.go.jp/ns/core/rdf#地理座標> ?locate.
      ?locate <http://imi.ipa.go.jp/ns/core/rdf#緯度> ?lat.
      ?locate <http://imi.ipa.go.jp/ns/core/rdf#経度> ?lng.
      filter(lang(?name) = "ja")
    }
    ')

    results
  end
end

実装の流れとしては

  1. 尾道市の飲食店データを得るためのクエリをSPARQLで書く。(ここがメイン)
  2. クエリから結果を返すself.all_queryを書く。
  3. self.all_queryの返り値をマッピングしてモデルのレコードインスタンスを生成するself.allを書く。

これでRestaurant.allを実行すれば尾道市の飲食店が全件取得できるようになる。

SPARQL難しい。

MNISTのバイナリをjpg化した

MNISTは大量の数字の画像データが入っていて便利だけど、バイナリデータなので画像化するのはちょっと面倒。
コピペで画像化できる便利なスクリプトが見当たらなかったので作ってみた。

書き捨てコードなのでクオリティは勘弁してください。

gist6eed8279e711d5eba6a9aa2415112a5b

必要なモジュールは適宜インストールしてください。

Rails+carrierwave+heroku+AWS S3で画像アップロードさせるときにハマったこと

# Gemfile

gem 'carrierwave'
gem 'fog-aws'
gem 'rmagick', require: 'RMagick'
# config/initializers/carrierwave.rb

if Rails.env.production?
  CarrierWave.configure do |config|
    config.storage = :fog
    config.fog_provider = 'fog/aws'
    config.fog_credentials = {
        :provider              => 'AWS',
        :aws_access_key_id     => ENV['S3_ACCESS_KEY_ID'],
        :aws_secret_access_key => ENV['S3_SECRET_KEY_ID'],
        :region                => ENV['S3_REGION'],
    }

    config.fog_directory = ENV['S3_BUCKET_NAME']
    config.fog_public = true
  end
else
  CarrierWave.configure do |config|
    config.storage = :file
  end
end

上記の Gemfilecarrierwave.rb を記述して git push heroku master すると以下のエラーが…

-----> Detecting rake tasks
-----> Preparing app for Rails asset pipeline
       Running: rake assets:precompile
       [DEPRECATION] requiring "RMagick" is deprecated. Use "rmagick" instead
       rake aborted!
       NameError: uninitialized constant CarrierWave::Storage::Fog
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/carrierwave-1.0.0/lib/carrierwave/uploader/configuration.rb:77:in `eval'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/carrierwave-1.0.0/lib/carrierwave/uploader/configuration.rb:77:in `eval'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/carrierwave-1.0.0/lib/carrierwave/uploader/configuration.rb:77:in `storage'
       /tmp/build_ef15e45299129328aea04600a8d0865a/config/initializers/carrierwave.rb:4:in `block in <top (required)>'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/carrierwave-1.0.0/lib/carrierwave/uploader/configuration.rb:158:in `configure'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/carrierwave-1.0.0/lib/carrierwave.rb:14:in `configure'
       /tmp/build_ef15e45299129328aea04600a8d0865a/config/initializers/carrierwave.rb:3:in `<top (required)>'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/railties-5.0.1/lib/rails/engine.rb:648:in `block in load_config_initializer'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.1/lib/active_support/notifications.rb:166:in `instrument'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/railties-5.0.1/lib/rails/engine.rb:647:in `load_config_initializer'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/railties-5.0.1/lib/rails/engine.rb:612:in `block (2 levels) in <class:Engine>'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/railties-5.0.1/lib/rails/engine.rb:611:in `each'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/railties-5.0.1/lib/rails/engine.rb:611:in `block in <class:Engine>'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/railties-5.0.1/lib/rails/initializable.rb:30:in `instance_exec'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/railties-5.0.1/lib/rails/initializable.rb:30:in `run'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/railties-5.0.1/lib/rails/initializable.rb:55:in `block in run_initializers'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/railties-5.0.1/lib/rails/initializable.rb:44:in `each'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/railties-5.0.1/lib/rails/initializable.rb:44:in `tsort_each_child'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/railties-5.0.1/lib/rails/initializable.rb:54:in `run_initializers'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/railties-5.0.1/lib/rails/application.rb:352:in `initialize!'
       /tmp/build_ef15e45299129328aea04600a8d0865a/config/environment.rb:5:in `<top (required)>'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/railties-5.0.1/lib/rails/application.rb:328:in `require_environment!'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/railties-5.0.1/lib/rails/application.rb:448:in `block in run_tasks_blocks'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/sprockets-rails-3.2.0/lib/sprockets/rails/task.rb:62:in `block (2 levels) in define'
       /tmp/build_ef15e45299129328aea04600a8d0865a/vendor/bundle/ruby/2.2.0/gems/rake-12.0.0/exe/rake:27:in `<top (required)>'
       Tasks: TOP => environment
       (See full trace by running task with --trace)

解決法を探っているとfogのissueに同じような内容のものを発見。

Declaring only fog-aws in Gemfile: uninitialized constant CarrierWave::Storage::Fog · Issue #3429 · fog/fog · GitHub

 

carrierwave.rbの始めでいくつかのファイルをrequireしろと書いてあったので

# config/initializers/carrierwave.rb

require 'carrierwave/storage/abstract'
require 'carrierwave/storage/file'
require 'carrierwave/storage/fog'

if Rails.env.production?
  CarrierWave.configure do |config|
    …

書き足してからgit push heroku masterすると無事デプロイすることができました。

めでたしめでたし。

多対多の相手レコード数の最小を指定するバリデーション

こんなクラス構造

class Hoge < ApplicationRecord
  has_many :hoge_foos
  has_many :foos, through: :hoge_foos
  accepts_nested_attributes_for :hoge_foos
end
class Foo < ApplicationRecord
  has_many :hoge_foos
  has_many :hoges, through: :hoge_foos
end
class HogeFoo < ApplicationRecord
  belongs_to :hoge
  belongs_to :foo
end

 

やりたいこと

  • hogeのフォームからfooをチェックボックスで複数選択して紐付かせる
  • fooを少なくとも1つは選択してほしい

 

結論

これでいける

class Hoge < ApplicationRecord
    -- 略 --
    validate :validate_foos

  def validate_foos
    errors.add(:foos, 'を1つ以上選択してください') if foos.size.zero?
  end
end
  • validates を使ってできないものなのか
  • できるだけ命名したくない

探したらあった!…だけど

class Hoge < ApplicationRecord
    --- 略 ---
    validates :hoge_foos, 
        length: { 
            minimum: 1,
            message: 'を1つ以上選択してください' 
        }
end

http://stackoverflow.com/questions/4486749/rails-has-many-minimum-collection-size-update-validation

  • イケてる気がする!
  • エラーメッセージが「hoge_foosを1つ以上選択してください」
  • なんか違う

対応策を考える

i18nをいじってhoge_foosの表記を変える
ja:
    activerecord:
        attributes:
            hoge:
                hoge_foos: 'foos'

これはやったらダメな気がする


i18n%{attribute} を非表示にする
ja:
    errors:
    format: "%{message}"

全てのバリデーションのattributeが消えるため被害範囲が大きいのでダメ
Rails3のときはattributeを表示させなくするgemがあったらしい

 

まとめ

  • レールに乗っかるためにはカスタムバリデーションメソッドを作るのが一番良さそう

 

RubyとSwiftにおける感嘆符/疑問符の扱いの違い

RubyとSwiftでは「!」と「?」が多用されますが使い方が違います。
Swiftでの使い方に中々慣れなかったので自分なりに対比させてまとめてみました。

元々Rubyを書いていてこれからSwiftを書き始める人やその逆の人の参考になればと思います。

 

最も違うところ

Rubyメソッド名に「!」,「?」を使う

Swiftは型名, 変数名に「!」,「?」を使う

 

Rubyはメソッド名に「!」,「?」を使う

Rubyではメソッドの処理内容をメソッド名から類推しやすくするために「!」「?」を使います。

Rubyリファレンスには以下のように記載されています。

「!」はメソッド名の一部です。慣用的に、 同名の(! の無い)メソッドに比べてより破壊的な作用をもつメソッド(例: tr と tr!)で使われます。
 
「?」はメソッド名の一部分です。 慣用的に、真偽値を返すタイプのメソッドを示すために使われます。

 

具体例を示します。

# 破壊的なメソッド
a = "string"
b = a
a.upcase!
p a   # => "STRING"
p b   # => “STRING"

# 非破壊的なメソッド
a = "string"
b = a
a = a.upcase
p a   # => "STRING"
p b   # => “string”

# 真偽を返す
“”.empty? #=> true

rubyのメソッド名で「!」「?」はアルファベットと同じ扱いをします。
なのでupcaseupcase!のような「!」「?」がついているメソッドとついていないメソッドは似た処理を行う別のメソッドになります。 同様の理由で非破壊メソッドのhogeメソッドしか定義してないときにhoge!を呼び出してもhogeの処理に似た破壊的メソッドが実行されるわけではありません(当たり前ですが)。

"メソッドの処理内容をメソッド名から類推しやすくする”ための機能なのでmustではありません。shouldです。 「!」がついていないけど破壊的な変更を行うメソッドや「?」がついていないけど真偽値を返すメソッドを定義してもエラーを吐かれることはありません。

 

Swiftは型名,変数名に「!」,「?」を使う

swiftでは変数の値がnilである状態を許容するかどうかを明確に区別するために「!」「?」を使います。
nilを許容するかどうかを明確に判断することによりnil関連のエラーに出会う可能性を極力減らすことができます。

具体例を示します。

# nilである状態を許容しない
var x = 3
x = nil     # error: nil cannot be assigned to type ‘Int’
print(x)    # 上の行でエラーしているので実行できない

var y: Int = 3
y = nil     # error: nil cannot be assigned to type ‘Int’
print(y)    # 上の行でエラーしているので実行できない


# nilである状態を許容する
var z: Int? = 3
z = nil
print(z)    # => nil

# -----------------

#Int型の変数にInt?型の値を代入する(unwrapしない)
var a: Int = 5
var b:Int? = 10
var c:Int? = nil
a = b       # error: value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'?
print(a)    # 上の行でエラーしているので実行できない
a = c       # error: value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'?
print(a)    # 上の行でエラーしているので実行できない

#Int型の変数にInt?型の値を代入する(unwrapする)
var d:Int = 5
var e:Int? = 10
var f:Int? = nil
d = e!
print(d)    # => 10
d = f!      # fatal error: unexpectedly found nil while unwrapping an Optional value
print(d)    # => 10 (d = e!の結果が残っている)

Intの変数にInt?の変数を直接代入することはできません。
それはIntInt?が別の型でありInt?の変数の値がnilの可能性があるためです。
変数名の後ろに「!」をつけることにより値がnilでないことを明示する(アンラップする)ことができます。 そしてアンラップした変数は「?」のついていない型に代入できます。

Swiftでの「!」「?」はmustです。
正しくラップ/アンラップしなければコンパイルエラーを吐きます。    

Swiftの「!」「?」はまだ理解しきれていない部分があるので代表的なところだけを紹介しました。
この記事がかなり詳しいです。
[Swift] Optional 型についてのまとめ Ver2 - Qiita