1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Multiscale 23f(数値計算におけるマルチスケール)

Last updated at Posted at 2023-09-20

name

ソフトウェア開発での必須スキルとなるTDD(test driven development, テスト駆動開発), class, refactoringを,Ruby言語で習得する

zoom link

  • ミーティングID: 822 0399 4456
  • パスコード: 473581

最終課題

RubyでなんかCLA(自分の作業に便利な)を作って!

  • その作ったexecutableなCLAをgithubにあげる
  • README.mdで
    • 使用前の問題点
    • 使用法
    • 使ったcodeの簡単な解説
    • 使用後どれほど効率が上がったか
    • を書く
  • LUNAにpdfを提出
    • A4, 1-2pagesにまとめて
    • citationをちゃんとしてね
    • github(publicでなくていい)のlinkをcitationに
  • githubのcollaboratorに担当者のidを入れてください.
    • わからなんだらお問い合わせください
  • 提出期限は,24/1/17 24:00です.

Schedule, text and movie

data text title memo 動画
d1 (9/20) TDD(preface) Intro, chat GPT memo link
d2 (9/27) TDD(intro) my_help, six things link
d3 (10/4) TDD(c1 , c2 ) TDD by Ruby link
d4 (10/11) TDD(c3,c4,c5) link
d5 (10/18) TDD(c6, c7, c8, c9, c10) link
d6 (10/25) TDD(c11, c12,) link
d7 (11/1) TDD()
d8 (11/8) TDD( c13, c14 ) link
d9 (11/15) TDD( c15, c16 ) link
Pattern( Matz template,
d10(11/22) strategy, link
d11(11/29) observer, factory Russ Olsen(J) link
d12(12/6) CoC, DSL(Rakefile) gem 作成 link
d13(12/13) FSM qiita link

d9-

Kent BeckのTDDを読み込んでどうやったやろ.私が初めて読んだ時の感想は,

  • TDDバンザイ
  • Clean code that works.
  • Divide and Conquer, baby
  • Red, Green, Refactoringってそういう意味やったんや

なんかです.すごいprogram codeは何度かみたことがあって,どうやるんやろ?って思ってたんですが,それがbottom upで作られたと思うとなんとなくそのコンセプトを征服できたみたいで理解が進むようになりました.

さて,デザインとか,アーキテクチャというのは後でついてくるものというのは,実感できたと思うのですが,それでも知ってないと発明する必要があって,それはNIHなんでダメですよね.

そこで,トップダウンの典型になるデザインパターンを紹介します.まずは,Rubyの父のMatzの言葉を読んでください.デザインパターンの本質が「名前」であると看破してます.

d7(11/1)

interface Expression
ask 'JavaのinterfaceをRubyで実装する方法を教えて' on Bing,

Javaのinterfaceは、特定のメソッドを持つことを強制するための契約のようなものです。しかし、Rubyはダックタイピングと呼ばれる概念を使用しており、クラスが特定のメソッドに応答するかどうかは各クラスに委ねられています。そのため、RubyにはJavaのようなinterfaceは存在しません。

ただし、Rubyではモジュールを使用してJavaのinterfaceに似た機能を実現することができます。モジュール内でメソッドを定義し、そのモジュールをクラスにミックスインすることで、クラスが特定のメソッドを持つことを保証することができます。

qiita JavaのinterfaceをRubyで実装する方法を教えて
https://ruby-processing.github.io/JRubyArt/modules/interface

従って,Javaでは型定義が必要なので便利だが,RubyではExpressionを明示する必要はない.

  • c14のPairのところでやめた.

以下は最終版

# frozen_string_literal: true

require_relative "tdd_example4/version"

module TddExample4
  class Pair
    def initialize(from, to)
      @from = from
      @to = to
    end
=begin
    def equals(object)
      pair = Pair.new(object)
      return from.equals(pair.from) && to.equals(pair.to)
    end
=end
    def hashcode()
      return 0
    end
  end
  class Sum
    attr_reader :augend, :addend
    def initialize(augend, addend)
      @augend = augend
      @addend = addend
    end
    def reduce(bank, to)
      amount = @augend.reduce(bank, to).amount +
               @addend.reduce(bank, to).amount
      return Money.new(amount, to)
    end
  end
  module Expression
    # Ruby implementation of Java's interface, but ...
  end
  class Bank
    def initialize
      @rates = {}
    end

    # include Expression
    def add_rate(from, to, rate)
      @rates[Pair.new(from, to).hashcode] = rate
    end
    def reduce(source, to)
=begin
      if source.class == Money
        return source.reduce(to)
      end
      sum = source # not new
=end
      return source.reduce(self, to) #Money.new(10).dollar
    end
    def rate(from, to)
      return 1 if from == to
      return @rates[Pair.new(from, to).hashcode]
#      return (from=='CHF' && to=='USD') ? 2 : 1
    end
  end
  class Money
    public attr_reader :amount
    public attr_reader :currency
    
    def initialize(amount, currency=nil)
      @amount = amount
      @currency = currency
    end
    def reduce(bank, to)
      rate = bank.rate(@currency, to)
      return Money.new(@amount/rate, to) #self
    end

    def +(addend) = Sum.new(self, addend)
#      return Money.new(@amount + addend.amount, currency)
    
    def ==(object)
      money = object
      return @amount == money.amount &&
        self.currency == money.currency
    end

    def dollar = Money.new(@amount, 'USD')
    def franc = Money.new(@amount, 'CHF')

    def times(multiplier)
      return Money.new(@amount * multiplier, @currency)
    end
  end
end
# frozen_string_literal: true

require "test_helper"

class TddExample4Test < Test::Unit::TestCase
  include TddExample4
  test "VERSION" do
    assert do
      ::TddExample4.const_defined?(:VERSION)
    end
  end

  test "something useful" do
    #    assert_equal("expected", "actual")
    assert_equal("expected", "expected")
  end

  test "mixed addition" do
    five_bucks = Money.new(5).dollar
    ten_franc = Money.new(10).franc
#    sum = Sum.new(five_bucks, ten_franc) # expression
    bank = Bank.new()
    bank.add_rate('CHF', 'USD', 2)
    result = bank.reduce(five_bucks + ten_franc, 'USD')
    assert_equal(Money.new(10).dollar, result)
  end
  test "identity rate" do
    assert_equal(1, Bank.new.rate('USD', 'USD'))
  end
  test "plus returns sum" do
    five = Money.new(5).dollar
    sum = five + five # expression
    assert_equal(five, sum.augend)
    assert_equal(five, sum.addend)
  end

  test "reduce money different currency" do
    bank = Bank.new()
    bank.add_rate('CHF', 'USD', 2)
    result = bank.reduce(Money.new(2).franc, 'USD')
    assert_equal(Money.new(1).dollar, result)
  end

  test "bank returns reduce sum" do
    three_usd = Money.new(3).dollar
    four_usd = Money.new(4).dollar
    sum = Sum.new(three_usd, four_usd) # expression
    bank = Bank.new()
    result = bank.reduce(sum, 'USD')
    assert_equal(Money.new(7).dollar, result)
  end

  test "reduce money" do
    bank = Bank.new()
    result = bank.reduce(Money.new(1).dollar, 'USD')
    assert_equal(Money.new(1).dollar, result)
  end

  test "simple addition" do
    five = Money.new(5).dollar
    sum = five + five # expression
    bank = Bank.new
    reduced = bank.reduce(sum, 'USD')
    assert_equal(Money.new(10).dollar, reduced)
#    assert_equal(Money.new(10).dollar, sum)
  end

  test "currency" do
    assert_equal 'USD',  Money.new(1).dollar.currency
    assert_equal 'CHF',  Money.new(1).franc.currency
  end

  test "equality" do
    assert_true  Money.new(5).dollar == Money.new(5).dollar
    assert_false Money.new(5).dollar == Money.new(6).dollar
    assert_true  Money.new(5).franc == Money.new(5).franc
    assert_false Money.new(5).franc == Money.new(6).franc
    assert_false Money.new(5).franc == Money.new(5).dollar
  end


  test "multiplication" do
    five = Money.new(5).dollar
    assert_true Money.new(10).dollar == five.times(2)
    assert_true Money.new(15).dollar == five.times(3)
  end

  test "Franc multiplication" do
    five = Money.new(5).franc
    assert_true Money.new(10).franc == five.times(2)
    assert_true Money.new(15).franc == five.times(3)
  end
end

d6(10/25)

c12, 13

Expressionを作った.これで,interfaceが...できるか?? ようわからんな.というところ

whole todo[10/16]

  • $5 + 10 CHF = $10 if rate is 2:1
  • $5+$5=$10
  • Return Money from $5 + $5
  • [X] $5 * 2 $10
  • [X] Make "amount' private
  • [X] class Dollar side-effects?
  • Money rounding?
  • [X] equals()
  • hashCode()
  • Equal null
  • Equal object
  • [X] 5 CHF * 2 = 10 CHF
  • [X] Common times
  • [X] Dollar/Franc duplication
  • [X] Common equals
  • [X] Compare Francs with Dollars
  • [X] Currency?
  • Delete Franc multiplication?

current codes

Moneyクラスへの統合が済んだので,codeはスッキリ.Kent本にはありませんが,Ruby独自の仕様でさらに読みやすくできます.その辺りから始めて,本丸(フランとドルの計算)へ突き進んでいきます.

# frozen_string_literal: true

require_relative "tdd_example4/version"

module TddExample4
  class Money
    protected attr_reader :amount
    def initialize(amount, currency=nil)
      @amount = amount
      @currency = currency
    end

    def equals(object)
      money = object
#      p [@amount, self.class, ":", money.amount, money.class]
      return @amount == money.amount &&
        self.currency == money.currency
    end
    def dollar()
      return Money.new(@amount, 'USD')
    end
    def franc()
      return Money.new(@amount, 'CHF')
    end
    def currency
      return @currency
    end
    def times(multiplier)
      return Money.new(@amount * multiplier, @currency)
    end
  end
end

# frozen_string_literal: true

require "test_helper"

class TddExample4Test < Test::Unit::TestCase
  include TddExample4
  test "VERSION" do
    assert do
      ::TddExample4.const_defined?(:VERSION)
    end
  end

  test "something useful" do
    #    assert_equal("expected", "actual")
    assert_equal("expected", "expected")
  end

  
  test "currency" do
    assert_equal('USD',  Money.new(1).dollar.currency() )
    assert_equal('CHF',  Money.new(1).franc.currency() )
  end

  test "equality" do
    assert_true( Money.new(5).dollar.equals( Money.new(5).dollar ) )
    assert_false( Money.new(5).dollar.equals( Money.new(6).dollar ) )
    assert_true( Money.new(5).franc.equals( Money.new(5).franc ) )
    assert_false( Money.new(5).franc.equals( Money.new(6).franc ) )
    assert_false( Money.new(5).franc.equals( Money.new(5).dollar ) )
  end


  test "multiplication" do
    five = Money.new(5).dollar
    assert_true( Money.new(10).dollar.equals( five.times(2) ) )
    assert_true( Money.new(15).dollar.equals( five.times(3) ) )
  end

  test "Franc multiplication" do
    five = Money.new(5).franc
    assert_true( Money.new(10).franc.equals( five.times(2) ) )
    assert_true( Money.new(15).franc.equals( five.times(3) ) )
  end
end

d5(10/18) c6-c10

current codes

5日目を始める時のcodeの現況はこんな感じ.

  1. FrancをDollarからコピペで作ったばかり

で,この段階としては最も大きくなっています.このあと,Moneyクラスに統合していくんだけど,作業内容は,Kentの言葉"Remove duplication(in c5)"が最も象徴的.でも,単なる重複削除ではなく,その思考法が大事.super/sub class, factory, currency(class but string)などの言葉を覚えておくと,自作コードが拡張性も見据えてオシャレになる.

# frozen_string_literal: true

require_relative "tdd_example3/version"

module TddExample3
  class Error < StandardError; end
  # Your code goes here...
  def hello
    return 'hello'
  end

  class Dollar
    protected attr_reader :amount
    def initialize(amount)
      @amount = amount
    end
    def times(multiplier)
      return Dollar.new(@amount * multiplier)
    end
    def equals(object)
      dollar = object
      return @amount == dollar.amount
    end
  end
  class Franc
    protected attr_reader :amount
    def initialize(amount)
      @amount = amount
    end
    def times(multiplier)
      return Franc.new(@amount * multiplier)
    end
    def equals(object)
      franc = object
      return @amount == franc.amount
    end
  end
end
# frozen_string_literal: true

require "test_helper"

class TddExample3Test < Test::Unit::TestCase
  include TddExample3
  test "VERSION" do
    assert do
      ::TddExample3.const_defined?(:VERSION)
    end
  end

  test "equality" do
    assert_true Dollar.new(5).equals Dollar.new(5)
    assert_false Dollar.new(5).equals Dollar.new(6)
  end
  test 'multiplication' do
    five = Dollar.new(5)
    assert_true Dollar.new(10).equals five.times(2)
    assert_true Dollar.new(15).equals five.times(3)
  end

  test 'franc multiplication' do
    five = Franc.new(5)
    assert_true Franc.new(10).equals five.times(2)
    assert_true Franc.new(15).equals five.times(3)
  end
end

c10 Interesting Times

  • [X] Common times
  • [X] Currency?

c9 Times We're Livin' In

  • Currency!!

c8 Makin' Objects

c7 Apples and Oranges

  • [X] Compare Francs with Dollars
  • Currency?

c6 Equality

  • [X] Dollar/Franc duplication
  • [X] Common equals

d4(10/11) c1-4 again

c5 Franc-ly Speaking[5/13]

  • Dollar/Franc duplication

c4 Privacy

  • $5 + 10 CHF = $10 if rate is 2:1
  • Make "amount' priate
  • [X] class Dollar side-effects?
  • Money rounding?
  • [X] equals()
  • hashCode()
  • Equal null
  • Equal object

c3 Equality for All[/]

  • $5 + 10 CHF = $10 if rate is 2:1

  • Make "amount' priate

  • [X] class Dollar side-effects?

  • Money rounding?

  • [X] equals()

  • hashCode()

  • Triangle

c2 Degenerate Objects[1/4]

  • $5 + 10 CHF = $10 if rate is 2:1
  • Make "amount' priate
  • [X] class Dollar side-effects?
  • Money rounding?
cat lib/tdd_example4.rb test/tdd_example4_test.rb 
# frozen_string_literal: true

require_relative "tdd_example4/version"

module TddExample4
  class Dollar
    attr_reader :amount
    def initialize(amount)
      @amount = amount
    end

    def times(multiplier)
      #      @amount *= multiplier
      return Dollar.new(@amount * multiplier)
    end
  end
end

# frozen_string_literal: true

require "test_helper"

class TddExample4Test < Test::Unit::TestCase
  include TddExample4
  test "VERSION" do
    assert do
      ::TddExample4.const_defined?(:VERSION)
    end
  end

  test "something useful" do
    #    assert_equal("expected", "actual")
    assert_equal("expected", "expected")
  end

  test "multiplication" do
    five = Dollar.new(5)
    product = five.times(2)
    assert_equal(10, product.amount)
    product = five.times(3)
    assert_equal(15, product.amount)
  end
end

c1 Multi_currency_money

  • 株価,shareから総資産を表示する.

  • $からスイスフランを追加.

  • [X] $5 * 2 $10

# frozen_string_literal: true

require "test_helper"

class TddExample4Test < Test::Unit::TestCase
  include TddExample4

  test "multiplication" do
    five = Dollar.new(5)
    five.times(2)
    assert_equal(10, five.amount)
  end
end
# frozen_string_literal: true

require_relative "tdd_example4/version"

module TddExample4
  class Error < StandardError; end
  # Your code goes here...
  class Dollar
    attr_reader :amount
    def initialize(amount)
      #      @amount = 5 * 2
      @amount = amount
    end

    def times(multiplier)
      @amount *= multiplier
    end
  end
end

d3 bundle, framework, test-unit

  • bundle

    gem install bundler # not bundle
    bundle gem -t test-unit tdd_example3 
    
      > cat ~/.bundle/config          (base) 
    ---
    BUNDLE_GEM__TEST: "test-unit"
    BUNDLE_GEM__COC: "true"
    BUNDLE_GEM__CI: "false"
    BUNDLE_GEM__CHANGELOG: "true"
    BUNDLE_GEM__MIT: "true"
    BUNDLE_GEM__LINTER: "false"
    
  • rake

  • bat

    [ ] hello

Text -> Multiscaleの意味

Multiscaleの意味

秋学期の間,講義に付き合っていただいてありがとうございます.コロナで君らの学生生活は埋まっちゃったと思うんですが,当初は,LUNAの提出先を開けるの忘れたり,Zoomの録画をどじったりして,ご迷惑をかけましたね.今でもですが...でも,教える側もこのドタバタを通して,いくつかのツールを有効に使うスキルを身につけました.Zoomとか手書き表示とかです.

さて,講義の題目のマルチスケールの意味についてです.この講義は20年やってきたんですが,当初は,物理のマルチスケール(オングストロームからマイクロメータ)で量子力学,分子動力学,モンテカルロ,有限要素法,フェーズフィールドといったそれぞれの手法を紹介していました.ところが,情報の学生に教えるにはあまりに物理なので,内容を再構成しようと思って徐々に変えてきました.そして今秋は,「コードもマルチスケールじゃね?」という方針に行きつきました.

粒度という概念を知っていますか?英語の直訳はgrain sizeですが,scaleと考えることもできます.コードでは,ループやifブロック,メソッド,クラスという感じで,対象とするコードの粒度が異なります.途中から紹介したデザインパターンは明らかにクラスレベルへの対処法をマニュアル化したものです.しかし,最後で紹介した新しいパターンとしての

  • CoC(Convention over configuration: 設定よりも規約)や
  • FSM(Finite state machine: 有限状態マシン,野田くん発音の指摘ありがとう,国際会議でも恥かいてます)

はアプリやメソッドレベルへのパターンです.さらに,テスト駆動開発は,全てのスケールで適用できます.そう考えると,RailsでブレークしたCoCパターンのうち,ファイルやディレクトリーの名前に意味を持たせるというのは,

適切な変数名を考えることをスケールを変えて適用した

と捉えることができます.

このように言葉の持つイメージや概念をマルチスケールに膨らませれば,新しいイノベーションの可能性がいくらでも転がっているようです.事実,私も本業の数値計算で,これらの手法をqueueなんかに繋げて,スパコンスケールで活用しています.さらに,マシンスケールでシステムにしちゃうとどこで何を書いたかが覚えてられるから不思議です.

これらは,前人が残してくれた知恵の賜物です.特に授業でも紹介した,

  • Kent Beck, 'Test-Driven Development by Example', (Pearson, 2003).
    • Kent Beck (著), 和田 卓人 (翻訳), 「テスト駆動開発」 (オーム社 2017).
  • Russ Olsen, 'Design Patterns in Ruby', (Addison-Wesley, 2007).
    • ラス・オルセン, 「Rubyによるデザインパターン」(ピアソン桐原 2009).
  • David Thomas, Andrew Hunt, 'The Pragmatic Programmer: Your journey to mastery, 20th Anniversary Edition' (Addison-Wesley Professional 2019).
    • David Thomas, Andrew Hunt, 「達人プログラマー(第2版): 熟達に向けたあなたの旅」(オーム社 2020).

には,ベストプラクティス(至宝の知恵)が詰まっています.結局,コーディングのスキルは,記憶を強化するコツの塊なんですよね.つまみ読みでいいんで,全文に目を通されることをお勧めします.あるいは,なんか行き詰まった時に読み返されることを.この講義が,いいコーディング習慣の一助になれば幸いです.

d1, Ruby環境構築

  • https://chat.openai.com
  • win11上のWSLでemacs, ruby, fishをインストールする方法を教えてください.
  • Ruby言語でmy_helpをインストールする方法を教えてください.

  • source ~/git_hub/ruby_docs/multi_scale_23/README.org
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?