diff --git a/fn.go b/fn.go index 1887919..962efc8 100644 --- a/fn.go +++ b/fn.go @@ -24,7 +24,7 @@ var ( // may outweigh the benefits of concurrent processing. This variable // specifies the minimum number of iterations per goroutine to ensure // an efficient division of labor. - minLoadPeGoroutine = 1024 + minLoadPerGoroutine = 1024 ) // Logicable is a special data type from which to determine the state of Trit @@ -234,11 +234,11 @@ func All[T Logicable](t ...T) Trit { found := &logicFoundValue{value: True} // If the length of the slice is less than or equal to - // the minLoadPeGoroutine, then we do not need + // the minLoadPerGoroutine, then we do not need // to use goroutines. if l := len(t); l == 0 { return False - } else if l/p < minLoadPeGoroutine { + } else if l/p < minLoadPerGoroutine { for _, v := range t { trit := logicToTrit(v) if trit.IsFalse() || trit.IsUnknown() { @@ -302,11 +302,11 @@ func Any[T Logicable](t ...T) Trit { found := &logicFoundValue{value: False} // If the length of the slice is less than or equal to - // the minLoadPeGoroutine, then we do not need + // the minLoadPerGoroutine, then we do not need // to use goroutines. if l := len(t); l == 0 { return False - } else if l/p < minLoadPeGoroutine { + } else if l/p < minLoadPerGoroutine { for _, v := range t { trit := logicToTrit(v) if trit.IsTrue() { @@ -548,11 +548,11 @@ func Known[T Logicable](ts ...T) Trit { found := &logicFoundValue{value: True} // If the length of the slice is less than or equal to - // the minLoadPeGoroutine, then we do not need + // the minLoadPerGoroutine, then we do not need // to use goroutines. if l := len(ts); l == 0 { return False - } else if l/p < minLoadPeGoroutine { + } else if l/p < minLoadPerGoroutine { for _, t := range ts { trit := logicToTrit(t) if trit == Unknown { @@ -664,3 +664,63 @@ func Random(up ...uint8) Trit { return False } + +// Consensus returns True if all input trits are True, False if all are False, +// and Unknown otherwise. +// +// Example usage: +// +// t1, t2, t3 := trit.True, trit.True, trit.Unknown +// result := Consensus(t1, t2, t3) +// // result will be Unknown, as not all trits are the same +func Consensus[T Logicable](trits ...T) Trit { + countT := 0 + countF := 0 + for _, x := range trits { + trit := logicToTrit(x) + switch trit.Val() { + case True: + countT++ + case False: + countF++ + default: + return Unknown + } + } + if countT == len(trits) { + return True + } else if countF == len(trits) { + return False + } + + return Unknown +} + +// Majority returns True if more than half of the input trits are True, False +// if more than half are False, and Unknown otherwise. +// +// Example usage: +// +// t1, t2, t3, t4 := trit.True, trit.True, trit.False, trit.Unknown +// result := Majority(t1, t2, t3, t4) +// // result will be True, as more than half of the trits are True +func Majority[T Logicable](trits ...T) Trit { + countT := 0 + countF := 0 + for _, x := range trits { + trit := logicToTrit(x) + switch trit.Val() { + case True: + countT++ + case False: + countF++ + } + } + if countT > len(trits)/2 { + return True + } else if countF > len(trits)/2 { + return False + } else { + return Unknown + } +} diff --git a/fn_test.go b/fn_test.go index 00da451..d737a03 100644 --- a/fn_test.go +++ b/fn_test.go @@ -167,7 +167,7 @@ func TestConvert(t *testing.T) { // TestAll tests the All function. func TestAll(t *testing.T) { ParallelTasks(2) - minLoadPeGoroutine = 20 + minLoadPerGoroutine = 20 tests := []struct { name string in []Trit @@ -218,7 +218,7 @@ func TestAll(t *testing.T) { // TestAny tests the Any function. func TestAny(t *testing.T) { ParallelTasks(2) - minLoadPeGoroutine = 20 + minLoadPerGoroutine = 20 tests := []struct { name string in []Trit @@ -988,7 +988,7 @@ func TestNeq(t *testing.T) { // TestKnown tests the Known function. func TestKnown(t *testing.T) { ParallelTasks(2) - minLoadPeGoroutine = 20 + minLoadPerGoroutine = 20 tests := []struct { name string in []Trit @@ -1107,7 +1107,7 @@ func TestRandom(t *testing.T) { } // Unknow - 0% - for i := 0; i < 100; i++ { + for i := 0; i < 10; i++ { result = Random(0) if result == Unknown { t.Errorf("Expected a random value as True or False, got %v", @@ -1116,10 +1116,58 @@ func TestRandom(t *testing.T) { } // Two arguments. - for i := 0; i < 100; i++ { + for i := 0; i < 10; i++ { result = Random(90, 5, 5) if result != Unknown { t.Errorf("Expected a random value as Unknown, got %v", result) } } + + result = Random(90, 60, 90) + if result != Unknown { + t.Errorf("Expected a random value as Unknown, got %v", result) + } +} + +// TestConsensus tests Consensus function. +func TestConsensus(t *testing.T) { + testCases := []struct { + name string + input []Trit + expected Trit + }{ + {"All True", []Trit{True, True, True}, True}, + {"All False", []Trit{False, False, False}, False}, + {"Mixed", []Trit{True, False, True}, Unknown}, + {"With Unknown", []Trit{True, True, Unknown}, Unknown}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if result := Consensus(tc.input...); result != tc.expected { + t.Fatalf("Expected %v, but got %v", tc.expected, result) + } + }) + } +} + +// TestMajority tests Majority function. +func TestMajority(t *testing.T) { + testCases := []struct { + name string + input []Trit + expected Trit + }{ + {"Majority True", []Trit{True, True, False}, True}, + {"Majority False", []Trit{False, False, True}, False}, + {"No Majority", []Trit{True, False, Unknown}, Unknown}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if result := Majority(tc.input...); result != tc.expected { + t.Fatalf("Expected %v, but got %v", tc.expected, result) + } + }) + } }