Go言語によるファジィ(Fuzzy)推論コード

2022年10月18日

C言語によるファジィ(Fuzzy)推論コード

をGo言語に移植してみました。

で、できるだけ、

「GO言語でクラスっぽいことをする」をレビューする

に近づけてみました。

コメントのPrint分は、C++のを残しています(面倒だったので)。あとenum型がないので、テキトーに文字列を使うことにしました。

以前のコードには、豪快なバグがありましたので、ソックリ差し替えします。

設定条件は以下の通りです(テーブルの内容は、負荷量です)

package main

import (
	"fmt"
	"os"
)

func max_2(a, b float64) float64 {
	if a > b {
		return a
	} else {
		return b
	}
}

func min_2(a, b float64) float64 {
	if a > b {
		return b
	} else {
		return a
	}
}

type condition_MF3 struct { // condition_MF3の基底クラス
	center  float64
	width   float64
	express string
}

func new_condition_MF3(_center, _width float64, _express string) *condition_MF3 {
	c3 := new(condition_MF3)
	c3.center = _center
	c3.width = _width
	c3.express = _express
	return c3
}

// 前件部メンバーシップ関数(山3つ)クラス
func (c3 *condition_MF3) func_X(_x float64) float64 {
	// x,yは、メンバーシップ関数上の座標を示す
	x := _x
	y := 0.0 // yの値は、必ず0以上1以下になる

	if c3.express == "LESS" {
		if x <= c3.center-c3.width {
			y = 1.0
		} else if x <= c3.center {
			y = -1.0 / c3.width * (x - c3.center)
		} else {
			y = 0.0
		}
	} else if c3.express == "COMMON" {
		if x <= c3.center-c3.width {
			y = 0.0
		} else if x <= c3.center {
			y = 1.0/c3.width*(x-c3.center) + 1.0
		} else if x <= c3.center+c3.width {
			y = -1.0/c3.width*(x-c3.center) + 1.0
		} else {
			y = 0.0
		}
	} else if c3.express == "MORE" {
		if x <= c3.center {
			y = 0.0
		} else if x <= c3.center+c3.width {
			y = 1.0 / c3.width * (x - c3.center)
		} else {
			y = 1.0
		}
	} else {
		fmt.Println("MF3: wrong expression")
		os.Exit(1)
	}
	return y
}

type condition_MF5 struct { // condition_MF5の基底クラス
	center  float64
	width   float64
	express string
}

func new_condition_MF5(_center, _width float64, _express string) *condition_MF5 {
	c5 := new(condition_MF5)
	c5.center = _center
	c5.width = _width
	c5.express = _express
	return c5
}

func (c5 *condition_MF5) func_X(_x float64) float64 {
	// 前件部メンバーシップ関数(山5つ)クラス
	// x,yは、メンバーシップ関数上の座標を示す
	x := _x
	y := 0.0 // yの値は、必ず0以上1以下になる

	if c5.express == "LESSLESS" {
		if x <= c5.center-2.0*c5.width {
			y = 1.0
		} else if x <= c5.center-c5.width {
			y = -1.0/c5.width*(x-(c5.center-2.0*c5.width)) + 1.0
		} else {
			y = 0.0
		}
	} else if c5.express == "LESS" {
		if x <= c5.center-2.0*c5.width {
			y = 0.0
		} else if x <= c5.center-c5.width {
			y = 1.0/c5.width*(x-(c5.center-c5.width)) + 1.0
		} else if x <= c5.center {
			y = -1.0/c5.width*(x-(c5.center-c5.width)) + 1.0
		} else {
			y = 0.0
		}
	} else if c5.express == "COMMON" {
		if x <= c5.center-c5.width {
			y = 0.0
		} else if x <= c5.center {
			y = 1.0/c5.width*(x-c5.center) + 1.0
		} else if x <= c5.center+c5.width {
			y = -1.0/c5.width*(x-c5.center) + 1.0
		} else {
			y = 0.0
		}
	} else if c5.express == "MORE" {
		if x <= c5.center {
			y = 0.0
		} else if x <= c5.center+c5.width {
			y = 1.0/c5.width*(x-(c5.center+c5.width)) + 1.0
		} else if x <= c5.center+2.0*c5.width {
			y = -1.0/c5.width*(x-(c5.center+c5.width)) + 1.0
		} else {
			y = 0.0
		}
	} else if c5.express == "MOREMORE" {
		if x <= c5.center+c5.width {
			y = 0.0
		} else if x <= c5.center+2.0*c5.width {
			y = 1.0/c5.width*(x-(c5.center+2.0*c5.width)) + 1.0
		} else {
			y = 1.0
		}
	} else {
		fmt.Println("MF5 func_X(): wrong expression")
		os.Exit(1)
	}

	return y
}

/////////////////////////////

type action_MF5 struct { // condition_MF5の基底クラス
	center  float64
	width   float64
	express string
	x       float64
	y       float64
}

func new_action_MF5(_center, _width float64, _express string) *action_MF5 {
	a5 := new(action_MF5)
	a5.center = _center
	a5.width = _width
	a5.express = _express

	if a5.express == "LESSLESS" {
		a5.x = a5.center - 2.0*a5.width
	} else if a5.express == "LESS" {
		a5.x = a5.center - a5.width
	} else if a5.express == "COMMON" {
		a5.x = a5.center
	} else if a5.express == "MORE" {
		a5.x = a5.center + a5.width
	} else if a5.express == "MOREMORE" {
		a5.x = a5.center + 2.0*a5.width
	} else {
		fmt.Println("new_action_MF5: wrong scale expression")
		os.Exit(-1)
	}

	a5.y = 0.0

	return a5
}

// 後件部メンバーシップ関数(山3つ)クラス
func (a5 *action_MF5) func_Y() float64 {
	// x,yは、メンバーシップ関数上の座標を示す

	return a5.y
}

func (a5 *action_MF5) func_Max(b float64) {
	a5.y = max_2(b, a5.y)
}

func (a5 *action_MF5) func_X() float64 {
	return a5.x
}

func complain_reasoning(dis, age float64) float64 {

	// Walking(前件部)
	Walk_Less := new_condition_MF3(1.4, 0.4, "LESS")
	Walk_Common := new_condition_MF3(1.4, 0.4, "COMMON")
	Walk_More := new_condition_MF3(1.4, 0.4, "MORE")

	// Age(前件部)
	Age_LessLess := new_condition_MF5(42, 15, "LESSLESS")
	Age_Less := new_condition_MF5(42, 15, "LESS")
	Age_Common := new_condition_MF5(42, 15, "COMMON") // 中央が 42歳
	Age_More := new_condition_MF5(42, 15, "MORE")
	Age_MoreMore := new_condition_MF5(42, 15, "MOREMORE")

	// Complain(後件部)
	Complain_LessLess := new_action_MF5(0.5, 0.25, "LESSLESS") // 不満の中央値が0.5   0.0/0.25/0.50/0.75/1.00 の5段階

	Complain_Less := new_action_MF5(0.5, 0.25, "LESS")
	Complain_Common := new_action_MF5(0.5, 0.25, "COMMON")
	Complain_More := new_action_MF5(0.5, 0.25, "MORE")
	Complain_MoreMore := new_action_MF5(0.5, 0.25, "MOREMORE")

	// [ルール00] 歩行距離:少0 年令:子供0
	Rule00 := min_2(Walk_Less.func_X(dis), Age_LessLess.func_X(age))
	Complain_LessLess.func_Max(Rule00) // 後件部は上書きされていく
	//fmt.Println("Rule00", Rule00)

	// [ルール01] 歩行距離:少0 年令:若年1
	Rule01 := min_2(Walk_Less.func_X(dis), Age_Less.func_X(age))
	Complain_LessLess.func_Max(Rule01) // 後件部は上書きされていく
	//fmt.Println("Rule01", Rule01)

	// [ルール02] 歩行距離:少0 年令:壮年2
	Rule02 := min_2(Walk_Less.func_X(dis), Age_Common.func_X(age))
	Complain_Common.func_Max(Rule02) // 後件部は上書きされていく
	//fmt.Println("Rule02", Rule02)

	// [ルール03] 歩行距離:少0 年令:高齢3
	Rule03 := min_2(Walk_Less.func_X(dis), Age_More.func_X(age))
	Complain_Common.func_Max(Rule03) // 後件部は上書きされていく
	//fmt.Println("Rule03", Rule03)

	// [ルール04] 歩行距離:少0 年令:老齢4
	Rule04 := min_2(Walk_Less.func_X(dis), Age_MoreMore.func_X(age))
	Complain_More.func_Max(Rule04) // 後件部は上書きされていく
	//fmt.Println("Rule04", Rule04)

	// [ルール10] 歩行距離:普通1 年令:子供0
	Rule10 := min_2(Walk_Common.func_X(dis), Age_LessLess.func_X(age))
	Complain_LessLess.func_Max(Rule10) // 後件部は上書きされていく
	//fmt.Println("Rule10", Rule10)

	// [ルール11] 歩行距離:普通1 年令:若年1
	Rule11 := min_2(Walk_Common.func_X(dis), Age_Less.func_X(age))
	Complain_Less.func_Max(Rule11) // 後件部は上書きされていく
	//fmt.Println("Rule11", Rule11)

	// [ルール12] 歩行距離:普通1 年令:壮年2
	Rule12 := min_2(Walk_Common.func_X(dis), Age_Common.func_X(age))
	Complain_Common.func_Max(Rule12) // 後件部は上書きされていく
	//fmt.Println("Rule12", Rule12)

	// [ルール13] 歩行距離:普通1 年令:高齢3
	Rule13 := min_2(Walk_Common.func_X(dis), Age_More.func_X(age))
	Complain_More.func_Max(Rule13) // 後件部は上書きされていく
	//fmt.Println("Rule13", Rule13)

	// [ルール14] 歩行距離:普通1 年令:老齢4
	Rule14 := min_2(Walk_Common.func_X(dis), Age_MoreMore.func_X(age))
	Complain_MoreMore.func_Max(Rule14) // 後件部は上書きされていく
	//fmt.Println("Rule14", Rule14)

	// [ルール20] 歩行距離:多2 年令:こども0
	Rule20 := min_2(Walk_More.func_X(dis), Age_LessLess.func_X(age))
	Complain_Less.func_Max(Rule20) // 後件部は上書きされていく
	//fmt.Println("Rule20", Rule20)

	// [ルール21] 歩行距離:多2 年令:若年1
	Rule21 := min_2(Walk_More.func_X(dis), Age_Less.func_X(age))
	Complain_Common.func_Max(Rule21) // 後件部は上書きされていく
	//fmt.Println("Rule21", Rule21)

	// [ルール22] 歩行距離:多2 年令:壮年2
	Rule22 := min_2(Walk_More.func_X(dis), Age_Common.func_X(age))
	Complain_More.func_Max(Rule22) // 後件部は上書きされていく
	//fmt.Println("Rule22", Rule22)

	// [ルール23] 歩行距離:多2 年令:高齢3
	Rule23 := min_2(Walk_More.func_X(dis), Age_More.func_X(age))
	Complain_MoreMore.func_Max(Rule23) // 後件部は上書きされていく
	//fmt.Println("Rule23", Rule23)

	// [ルール24] 歩行距離:多2 年令:老齢4
	Rule24 := min_2(Walk_More.func_X(dis), Age_MoreMore.func_X(age))
	Complain_MoreMore.func_Max(Rule24) // 後件部は上書きされていく
	//fmt.Println("Rule24", Rule24)

	// 推論計算
	numerator :=
		Complain_LessLess.func_X()*Complain_LessLess.func_Y() +
			Complain_Less.func_X()*Complain_Less.func_Y() +
			Complain_Common.func_X()*Complain_Common.func_Y() +
			Complain_More.func_X()*Complain_More.func_Y() +
			Complain_MoreMore.func_X()*Complain_MoreMore.func_Y()

	denominator :=
		Complain_LessLess.func_Y() +
			Complain_Less.func_Y() +
			Complain_Common.func_Y() +
			Complain_More.func_Y() +
			Complain_MoreMore.func_Y()

	complain := numerator / denominator

	return complain

}

2022年10月18日2022/09,江端さんの技術メモ

Posted by ebata