master > master: src go - algorithmen + display methoden hinzugefügt
This commit is contained in:
173
code/golang/internal/algorithms/search/poison/poison.go
Normal file
173
code/golang/internal/algorithms/search/poison/poison.go
Normal file
@@ -0,0 +1,173 @@
|
||||
package poison
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* IMPORTS
|
||||
* ---------------------------------------------------------------- */
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"ads/internal/core/logging"
|
||||
"ads/internal/core/metrics"
|
||||
"ads/internal/core/utils"
|
||||
)
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* GLOBAL VARIABLES/CONSTANTS
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
//
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* ALGORITHM find poison
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
/*
|
||||
Inputs: L = Liste von Getränken: durch boolesche Werte wird dargestellt, ob ein Getränk vergiftet ist.
|
||||
|
||||
Annahme: Genau ein Getränk sei vergiftet.
|
||||
|
||||
Outputs: Der Index des vergifteten Getränks, falls es eines gibt, ansonsten -1.
|
||||
|
||||
NOTE: Zeitkosten hier messen nur die Anzahl der Vorkoster.
|
||||
*/
|
||||
func FindPoison(L []int) int {
|
||||
logging.LogDebug("Bereite Vorkoster vor")
|
||||
n := len(L)
|
||||
testers := [][]int{}
|
||||
for i := 0; i < n; i++ {
|
||||
metrics.AddSpaceCost()
|
||||
logging.LogDebug(fmt.Sprintf("Füge Vorkoster hinzu, der nur Getränk %[1]v testet.", i))
|
||||
testers = append(testers, []int{i})
|
||||
}
|
||||
logging.LogDebug("Warte auf Effekte")
|
||||
effects := waitForEffects(L, testers)
|
||||
logging.LogDebug("Effekte auswerten, um vergiftete Getränke zu lokalisieren.")
|
||||
poisened := evaluateEffects(testers, effects)
|
||||
if len(poisened) > 0 {
|
||||
return poisened[0]
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* ALGORITHM find poison fast
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
/*
|
||||
Inputs: L = Liste von Getränken: durch boolesche Werte wird dargestellt, ob ein Getränk vergiftet ist.
|
||||
|
||||
Annahme: Genau ein Getränk sei vergiftet.
|
||||
|
||||
Outputs: Der Index des vergifteten Getränks, falls es eines gibt, ansonsten -1.
|
||||
|
||||
NOTE: Zeitkosten hier messen nur die Anzahl der Vorkoster.
|
||||
*/
|
||||
func FindPoisonFast(L []int) int {
|
||||
logging.LogDebug("Bereite Vorkoster vor")
|
||||
n := len(L)
|
||||
p := utils.LengthOfBinary(n)
|
||||
testers := [][]int{}
|
||||
// Für jedes Bit i=0 bis p-1 ...
|
||||
for i := 0; i < p; i++ {
|
||||
tester0 := []int{}
|
||||
tester1 := []int{}
|
||||
for k := 0; k < n; k++ {
|
||||
if utils.NthBit(k, i) == 0 {
|
||||
tester0 = append(tester0, k)
|
||||
} else {
|
||||
tester1 = append(tester1, k)
|
||||
}
|
||||
}
|
||||
/*
|
||||
* NOTE: tester1 ist virtuell: aus den Effekten auf tester0 und den Annahmen
|
||||
* lassen sich die Effekte auf tester0 erschließen.
|
||||
* Darum zählen wir nicht 2 sondern 1 Vorkoster.
|
||||
*/
|
||||
metrics.AddSpaceCost(1)
|
||||
logging.LogDebug(fmt.Sprintf("Füge Vorkoster hinzu, der alle Getränke k testet mit %[1]v. Bit von k = 0.", i))
|
||||
testers = append(testers, tester0)
|
||||
testers = append(testers, tester1)
|
||||
}
|
||||
logging.LogDebug("Warte auf Effekte")
|
||||
effects := waitForEffects(L, testers)
|
||||
logging.LogDebug("Effekte auswerten, um vergiftete Getränke zu lokalisieren.")
|
||||
poisened := evaluateEffects(testers, effects)
|
||||
if len(poisened) > 0 {
|
||||
return poisened[0]
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* AUXILIARY METHOD wait for effects, evaluate effects
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
/*
|
||||
Inputs:
|
||||
|
||||
- L = Liste von Getränken: durch boolesche Werte wird dargestellt, ob ein Getränk vergiftet ist.
|
||||
|
||||
- testers = Liste von Vorkostern. Jeder Vorkoster kostet eine 'Teilliste' der Getränke.
|
||||
|
||||
Outputs: effects = eine Liste, die jedem Vorkoster zuordnet, wie viele vergiftete Getränke er konsumiert hat.
|
||||
*/
|
||||
func waitForEffects(L []int, testers [][]int) []int {
|
||||
m := len(testers)
|
||||
effects := make([]int, m)
|
||||
for i, tester := range testers {
|
||||
effect := 0
|
||||
for _, k := range tester {
|
||||
effect += L[k]
|
||||
}
|
||||
effects[i] = effect
|
||||
}
|
||||
return effects
|
||||
}
|
||||
|
||||
/*
|
||||
Inputs:
|
||||
|
||||
- testers = Liste von Vorkostern. Jeder Vorkoster kostet eine 'Teilliste' der Getränke.
|
||||
|
||||
- effects = eine Liste, die jedem Vorkoster zuordnet, wie viele vergiftete Getränke er konsumiert hat.
|
||||
|
||||
Annahmen: Vorkoster wurden so angewiesen, dass es garantiert ist, vergiftete Getränke zu finden, wenn es die gibt.
|
||||
|
||||
Outputs: Liste der Indexes aller vergifteten Getränke.
|
||||
*/
|
||||
func evaluateEffects(testers [][]int, effects []int) []int {
|
||||
var states = map[int]bool{}
|
||||
var poisened = []int{}
|
||||
|
||||
// Werte Effekte aus, um Gift zu lokalisieren:
|
||||
// Zuerst die Indexes der Getränke bei allen vergifteten Tester zusammenführen:
|
||||
for i, tester := range testers {
|
||||
// wenn Tester positiv testet, dann ist eines der von ihm probierten Getränks vergiftet
|
||||
if effects[i] > 0 {
|
||||
// markiere alle vom Tester probierten Getränke
|
||||
for _, k := range tester {
|
||||
states[k] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
// jetzt eliminieren wir alle Getränke, die von nicht vergifteten Testern konsumiert wurden:
|
||||
for i, tester := range testers {
|
||||
// wenn Tester negativ testet, dann ist KEINES der von ihm probierten Getränks vergiftet
|
||||
if effects[i] == 0 {
|
||||
// schließe alle vom Tester probierten Getränke aus
|
||||
for _, k := range tester {
|
||||
states[k] = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// was übrig bleibt sind die vergifteten Getränke, vorausgesetzt genug Vorkoster wurden ausgewählt
|
||||
for k, state := range states {
|
||||
if state {
|
||||
poisened = append(poisened, k)
|
||||
}
|
||||
}
|
||||
|
||||
return poisened
|
||||
}
|
||||
136
code/golang/internal/algorithms/search/poison/poison_fancy.go
Normal file
136
code/golang/internal/algorithms/search/poison/poison_fancy.go
Normal file
@@ -0,0 +1,136 @@
|
||||
package poison
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* IMPORTS
|
||||
* ---------------------------------------------------------------- */
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"ads/internal/core/metrics"
|
||||
"ads/internal/core/utils"
|
||||
"ads/internal/setup"
|
||||
)
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* GLOBAL VARIABLES/CONSTANTS
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
//
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* CHECKS
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
func preChecks(L []int, _ ...interface{}) error {
|
||||
s := utils.SumListInt(L)
|
||||
if !(s > 0) {
|
||||
return fmt.Errorf("Mindestens ein Getränk muss vergiftet sein!")
|
||||
} else if !(s <= 1) {
|
||||
return fmt.Errorf("Höchstens ein Getränk darf vergiftet sein!")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func postChecks(L []int, index int, _ ...interface{}) error {
|
||||
if !(index >= 0) {
|
||||
return fmt.Errorf("Der Algorithmus hat kein vergiftetes Getränk gefunden, obwohl per Annahme eines existiert.")
|
||||
} else if !(L[index] > 0) {
|
||||
return fmt.Errorf("Der Algorithmus hat das vergiftete Getränk nicht erfolgreich bestimmt.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* ALGORITHM find poison + Display
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
func FancyFindPoison(input_L []int) (int, error) {
|
||||
var name = "Giftsuche (O(n) Vorkoster)"
|
||||
var inputs = map[string]interface{}{
|
||||
"L": input_L,
|
||||
}
|
||||
var outputs map[string]interface{}
|
||||
var (
|
||||
output_index int
|
||||
)
|
||||
var err error
|
||||
|
||||
do_once := true
|
||||
for do_once {
|
||||
do_once = false
|
||||
setup.DisplayStartOfAlgorithm(name, inputs)
|
||||
metrics.RestartMetrics()
|
||||
|
||||
// Prechecks:
|
||||
err = preChecks(input_L)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
// Ausführung des Algorithmus:
|
||||
output_index = FindPoison(input_L)
|
||||
outputs = map[string]interface{}{
|
||||
"index": output_index,
|
||||
}
|
||||
|
||||
// Letzte Messages:
|
||||
setup.DisplayMetrics()
|
||||
setup.DisplayEndOfAlgorithm(outputs)
|
||||
|
||||
// Postchecks:
|
||||
err = postChecks(input_L, output_index)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return output_index, err
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* ALGORITHM find poison fast + Display
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
func FancyFindPoisonFast(input_L []int) (int, error) {
|
||||
var name = "Giftsuche (O(log(n)) Vorkoster)"
|
||||
var inputs = map[string]interface{}{
|
||||
"L": input_L,
|
||||
}
|
||||
var outputs map[string]interface{}
|
||||
var (
|
||||
output_index int
|
||||
)
|
||||
var err error
|
||||
|
||||
do_once := true
|
||||
for do_once {
|
||||
do_once = false
|
||||
setup.DisplayStartOfAlgorithm(name, inputs)
|
||||
metrics.RestartMetrics()
|
||||
|
||||
// Prechecks:
|
||||
err = preChecks(input_L)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
// Ausführung des Algorithmus:
|
||||
output_index = FindPoisonFast(input_L)
|
||||
outputs = map[string]interface{}{
|
||||
"index": output_index,
|
||||
}
|
||||
|
||||
// Letzte Messages:
|
||||
setup.DisplayMetrics()
|
||||
setup.DisplayEndOfAlgorithm(outputs)
|
||||
|
||||
// Postchecks:
|
||||
err = postChecks(input_L, output_index)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return output_index, err
|
||||
}
|
||||
Reference in New Issue
Block a user