Skip to content

Commit bbe704c

Browse files
committed
Updated performance
1 parent c7ebc15 commit bbe704c

File tree

3 files changed

+413
-11
lines changed

3 files changed

+413
-11
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ Here's an explanation of some key parts of this package:
189189

190190
- Provides methods default state (like Default, TrueIfUnknown, FalseIFUnknown etc.,) that check if the value of a Trit is Unknown and change its value based on the method called. For instance, TrueIfUnknown will set the Trit to True if its current value is Unknown.
191191

192-
- There are some methods (like IsFalse, IsUnknown, IsTrue, IsConfidence etc.,) that check the state of a Trit and return a boolean indicating if the Trit is in the corresponding state.
192+
- There are some methods (like IsFalse, IsUnknown, IsTrue, etc.,) that check the state of a Trit and return a boolean indicating if the Trit is in the corresponding state.
193193

194194
- Some methods perform various operations like assigning a value to a Trit (Set), returning the normalized value of a Trit (Val), normalizing the Trit in place (Norm), getting the integer representation of the Trit (Int), and getting the string representation of the Trit (String).
195195

fn.go

Lines changed: 257 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
package trit
22

33
import (
4+
"context"
45
"reflect"
6+
"runtime"
7+
"sync"
8+
)
9+
10+
var (
11+
// The parallelTasks the number of parallel tasks.
12+
parallelTasks = 1
13+
14+
// The maxParallelTasks is the maximum number of parallel tasks.
15+
maxParallelTasks = runtime.NumCPU() * 3
516
)
617

718
// Logicable is a special data type from which to determine the state of Trit
@@ -13,6 +24,66 @@ type Logicable interface {
1324
float32 | float64
1425
}
1526

27+
// The logicFoundValue is a helper struct that holds a boolean value
28+
// and a Mutex to protect it from concurrent access.
29+
//
30+
// They are used in the In function to detect the desired result
31+
// in a separate goroutine.
32+
type logicFoundValue struct {
33+
m sync.Mutex
34+
value Trit
35+
}
36+
37+
// SetValue sets a new value for the Found. It locks the Mutex before
38+
// changing the value and unlocks it after the change is complete.
39+
func (f *logicFoundValue) SetValue(value Trit) {
40+
f.m.Lock()
41+
defer f.m.Unlock()
42+
f.value = value
43+
}
44+
45+
// GetValue retrieves the current value of the Found. It locks the Mutex
46+
// before reading the value and unlocks it after the read is complete.
47+
func (f *logicFoundValue) GetValue() Trit {
48+
f.m.Lock()
49+
defer f.m.Unlock()
50+
return f.value
51+
}
52+
53+
// The init initializes the randomGenerator variable.
54+
func init() {
55+
parallelTasks = runtime.NumCPU() * 2
56+
}
57+
58+
// ParallelTasks returns the number of parallel tasks.
59+
//
60+
// If the function is called without parameters, it returns the
61+
// current value of parallelTasks.
62+
//
63+
// A function can receive one or more values for parallelTasks,
64+
// these values are added together to form the final result for
65+
// parallelTasks. If the new value for parallelTasks is less than
66+
// or equal to zero - it will be set to 1, if it is greater than
67+
// maxParallelTasks - it will be set to maxParallelTasks.
68+
func ParallelTasks(v ...int) int {
69+
if len(v) > 0 {
70+
n := 0
71+
for _, value := range v {
72+
n += value
73+
}
74+
75+
if n <= 0 {
76+
parallelTasks = 1
77+
} else if n > maxParallelTasks {
78+
parallelTasks = maxParallelTasks
79+
} else {
80+
parallelTasks = n
81+
}
82+
}
83+
84+
return parallelTasks
85+
}
86+
1687
// The logicToTrit function converts any logic type to Trit.
1788
func logicToTrit[T Logicable](v T) Trit {
1889
switch any(v).(type) {
@@ -133,14 +204,65 @@ func Convert[T Logicable](v T) Trit {
133204
// t := trit.All(trit.True, trit.True, trit.True)
134205
// fmt.Println(t.String()) // Output: True
135206
func All[T Logicable](t ...T) Trit {
136-
for _, v := range t {
137-
trit := logicToTrit(v)
138-
if trit.IsFalse() {
139-
return False
207+
var wg sync.WaitGroup
208+
209+
// Will use context to stop the rest of the goroutines
210+
// if the value has already been found.
211+
ctx, cancel := context.WithCancel(context.Background())
212+
defer cancel()
213+
214+
p := parallelTasks
215+
found := &logicFoundValue{value: True}
216+
217+
// If the length of the slice is less than or equal to
218+
// the number of parallel tasks, then we do not need
219+
// to use goroutines.
220+
if l := len(t); l == 0 {
221+
return False
222+
} else if l < p*2 {
223+
for _, v := range t {
224+
trit := logicToTrit(v)
225+
if trit.IsFalse() || trit.IsUnknown() {
226+
return False
227+
}
140228
}
229+
230+
return True
141231
}
142232

143-
return True
233+
chunkSize := len(t) / p
234+
for i := 0; i < p; i++ {
235+
wg.Add(1)
236+
237+
start := i * chunkSize
238+
end := start + chunkSize
239+
if i == p-1 {
240+
end = len(t)
241+
}
242+
243+
go func(start, end int) {
244+
defer wg.Done()
245+
246+
for _, b := range t[start:end] {
247+
trit := logicToTrit(b)
248+
// Check if the context has been cancelled.
249+
select {
250+
case <-ctx.Done():
251+
return
252+
default:
253+
}
254+
255+
if trit.IsFalse() || trit.IsUnknown() {
256+
found.SetValue(False)
257+
cancel() // stop all other goroutines
258+
return
259+
}
260+
}
261+
}(start, end)
262+
}
263+
264+
wg.Wait()
265+
return found.GetValue()
144266
}
145267

146268
// Any returns True if any of the trit-objects are True.
@@ -150,14 +272,66 @@ func All[T Logicable](t ...T) Trit {
150272
// t := trit.Any(trit.True, trit.False, trit.False)
151273
// fmt.Println(t.String()) // Output: True
152274
func Any[T Logicable](t ...T) Trit {
153-
for _, v := range t {
154-
trit := logicToTrit(v)
155-
if trit.IsTrue() {
156-
return True
275+
var wg sync.WaitGroup
276+
277+
// Will use context to stop the rest of the goroutines
278+
// if the value has already been found.
279+
ctx, cancel := context.WithCancel(context.Background())
280+
defer cancel()
281+
282+
p := parallelTasks
283+
found := &logicFoundValue{value: False}
284+
285+
// If the length of the slice is less than or equal to
286+
// the number of parallel tasks, then we do not need
287+
// to use goroutines.
288+
if l := len(t); l == 0 {
289+
return False
290+
} else if l < p*2 {
291+
for _, v := range t {
292+
trit := logicToTrit(v)
293+
if trit.IsTrue() {
294+
return True
295+
}
157296
}
297+
298+
return False
158299
}
159300

160-
return False
301+
chunkSize := len(t) / p
302+
for i := 0; i < p; i++ {
303+
wg.Add(1)
304+
305+
start := i * chunkSize
306+
end := start + chunkSize
307+
if i == p-1 {
308+
end = len(t)
309+
}
310+
311+
go func(start, end int) {
312+
defer wg.Done()
313+
314+
for _, b := range t[start:end] {
315+
trit := logicToTrit(b)
316+
317+
// Check if the context has been cancelled.
318+
select {
319+
case <-ctx.Done():
320+
return
321+
default:
322+
}
323+
324+
if trit.IsTrue() {
325+
found.SetValue(True)
326+
cancel() // stop all other goroutines
327+
return
328+
}
329+
}
330+
}(start, end)
331+
}
332+
333+
wg.Wait()
334+
return found.GetValue()
161335
}
162336

163337
// None returns True if none of the trit-objects are True.
@@ -333,6 +507,79 @@ func Neq[T, U Logicable](a T, b U) Trit {
333507
return ta.Neq(tb)
334508
}
335509

510+
// Known returns boolean true if all Trit-Like values has definiteness,
511+
// i.e. is either True or False.
512+
//
513+
// Example usage:
514+
//
515+
// a := trit.Known(trit.True, trit.False, trit.Unknown)
516+
// fmt.Println(a.String()) // Output: False
517+
//
518+
// b := trit.Known(trit.True, trit.True, trit.False)
519+
// fmt.Println(b.String()) // Output: True
520+
func Known[T Logicable](ts ...T) Trit {
521+
var wg sync.WaitGroup
522+
523+
// Will use context to stop the rest of the goroutines
524+
// if the value has already been found.
525+
ctx, cancel := context.WithCancel(context.Background())
526+
defer cancel()
527+
528+
p := parallelTasks
529+
found := &logicFoundValue{value: True}
530+
531+
// If the length of the slice is less than or equal to
532+
// the number of parallel tasks, then we do not need
533+
// to use goroutines.
534+
if l := len(ts); l == 0 {
535+
return False
536+
} else if l < p*2 {
537+
for _, t := range ts {
538+
trit := logicToTrit(t)
539+
if trit == Unknown {
540+
return False
541+
}
542+
}
543+
544+
return True
545+
}
546+
547+
chunkSize := len(ts) / p
548+
for i := 0; i < p; i++ {
549+
wg.Add(1)
550+
551+
start := i * chunkSize
552+
end := start + chunkSize
553+
if i == p-1 {
554+
end = len(ts)
555+
}
556+
557+
go func(start, end int) {
558+
defer wg.Done()
559+
560+
for _, b := range ts[start:end] {
561+
trit := logicToTrit(b)
562+
563+
// Check if the context has been cancelled.
564+
select {
565+
case <-ctx.Done():
566+
return
567+
default:
568+
}
569+
570+
if trit.IsUnknown() {
571+
found.SetValue(False)
572+
cancel() // stop all other goroutines
573+
return
574+
}
575+
}
576+
}(start, end)
577+
}
578+
579+
wg.Wait()
580+
return found.GetValue()
581+
}
582+
336583
// IsConfidence returns boolean true if all Trit-Like values has definiteness,
337584
// i.e. is either True or False.
338585
//

0 commit comments

Comments
 (0)