Skip to content

Commit

Permalink
Merge pull request #84 from bowen-xu/bug/83-distributor
Browse files Browse the repository at this point in the history
add OpenNARS-style Distributor in Bag
  • Loading branch information
bowen-xu authored Jan 11, 2024
2 parents ce41403 + f9c4270 commit 0632551
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 16 deletions.
2 changes: 1 addition & 1 deletion Tests/test_Bag.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def test_bag_take_task(self):
cnt1 += 1
elif task == task2:
cnt2 += 1
self.assertGreater(cnt1, 3*cnt2)
self.assertGreater(cnt1, cnt2)

bag.take_by_key(task1)
bag.take_by_key(task2)
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_NAL/test_NAL2.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def test_backward_inference(self):
tasks_derived = process_two_premises(
'<bird --> swimmer>. %1.00;0.90%',
'<{?1} --> swimmer>?',
6
20
)
self.assertTrue(
output_contains(tasks_derived, '<{?1} --> bird>?')
Expand Down
6 changes: 4 additions & 2 deletions Tests/test_NAL/test_NAL5.py
Original file line number Diff line number Diff line change
Expand Up @@ -785,16 +785,18 @@ def test_conditional_deduction_compound_eliminate_0(self):
tasks_derived = process_two_premises(
'<(&&,<robin --> [flying]>,<robin --> [with_wings]>) ==> <robin --> bird>>. %1.00;0.90%',
'<robin --> [flying]>. %1.00;0.90%',
2
10
)
self.assertTrue(
output_contains(tasks_derived, '<<robin --> [with_wings]> ==> <robin --> bird>>. %1.00;0.81%')
)

nars.reset()

tasks_derived = process_two_premises(
'<robin --> [flying]>. %1.00;0.90%',
'<(&&,<robin --> [flying]>,<robin --> [with_wings]>) ==> <robin --> bird>>. %1.00;0.90%',
2
10
)
self.assertTrue(
output_contains(tasks_derived, '<<robin --> [with_wings]> ==> <robin --> bird>>. %1.00;0.81%')
Expand Down
6 changes: 3 additions & 3 deletions Tests/test_NAL/test_NAL6.py
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,7 @@ def test_multiple_variables_introduction_1(self):
tasks_derived = process_two_premises(
'(&&,<#x --> key>,<{lock1} --> (/,open,#x,_)>). %1.00;0.90%',
'<{lock1} --> lock>. %1.00;0.90%',
10
20
)

self.assertTrue(
Expand Down Expand Up @@ -781,7 +781,7 @@ def test_second_variable_introduction_induction(self):
tasks_derived = process_two_premises(
'<<lock1 --> (/,open,$1,_)> ==> <$1 --> key>>. %1.00;0.90%',
'<lock1 --> lock>. %1.00;0.90%',
10
20
)

self.assertTrue(
Expand Down Expand Up @@ -864,7 +864,7 @@ def test_second_level_variable_unification_1_0(self):
tasks_derived = process_two_premises(
'<A ==> (&&,<#2 --> B>,C)>. %1.00;0.90%',
'<M --> B>. %1.00;0.90%',
10
20
)

self.assertTrue(
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_NAL/test_NAL7.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ def test_inference_on_tense_2(self):
tasks_derived = process_two_premises(
'<<(*,John,key_101) --> hold> =/> <(*,John,room_101) --> enter>>. %1.00;0.90%',
'<(*,John,room_101) --> enter>. :\: %1.00;0.90%',
10
30
)

self.assertTrue(
Expand Down
24 changes: 16 additions & 8 deletions pynars/NARS/DataStructures/_py/Bag.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from pynars.Narsese import Item, Task
from pynars.NAL.Functions.BudgetFunctions import *
from typing import Union, Callable, Any
from .Distributor import Distributor


class Bag:
Expand Down Expand Up @@ -49,11 +50,18 @@ def __init__(self, capacity: int, n_buckets: int = None, take_in_order: bool = T
take_in_order (bool): if True, an item is taken out in order within a bucket, otherwise a random item is taken out.
'''
self.capacity = capacity
self.pointer = 0 # Pointing to the Bag's current bucket number
self.take_in_order = take_in_order
self.item_lut = self.LUT(key=key) # look up table
self.n_levels = n_buckets if n_buckets is not None else Config.num_buckets
self.pointer = self.n_levels - 1 # Pointing to the Bag's current bucket number

self.distributor = Distributor.new(self.n_levels)

self.levels = tuple(list() for i in range(self.n_levels)) # initialize buckets between 0 and capacity

self.current_counter = 0
self.level_index = capacity % self.n_levels

# self.buckets = self.Depq(maxlen=self.n_buckets)
n_digits = int(math.log10(self.n_levels)) + 3

Expand All @@ -66,9 +74,12 @@ def map_priority(priority: float):

def take(self, remove = True) -> Item:
if len(self) == 0: return None

if self._is_current_level_empty():
self._move_to_next_nonempty_level()
if self._is_current_level_empty() or self.current_counter == 0:
self.pointer = self.distributor.pick(self.level_index)
self.level_index = self.distributor.next(self.level_index)
while self._is_current_level_empty():
self.pointer = self.distributor.pick(self.level_index)
self.level_index = self.distributor.next(self.level_index)

if self.take_in_order:
# take the first item from the current bucket
Expand All @@ -86,10 +97,7 @@ def take(self, remove = True) -> Item:
else:
item = self.levels[self.pointer][idx]

bucket_probability = self.pointer / self.n_levels
rnd = random.random() # [0.0, 1.0)
if rnd > bucket_probability:
self._move_to_next_nonempty_level()
self.current_counter = idx

return item

Expand Down
32 changes: 32 additions & 0 deletions pynars/NARS/DataStructures/_py/Distributor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from functools import lru_cache

"""
A pseudo-random number generator, used in Bag
"""
class Distributor:
@staticmethod
@lru_cache(maxsize=None)
def new(range_val):
'''Factory method for creating new Distributors with caching to avoid repeated calculations'''
return Distributor(range_val)

"""
For any number N < range, there is N+1 copies of it in the array, distributed as evenly as possible
"""
def __init__(self, range_val):
self.capacity = (range_val * (range_val + 1)) // 2
self.order = [-1] * self.capacity

index = 0
for rank in range(range_val, 0, -1):
for time in range(rank):
index = ((self.capacity // rank) + index) % self.capacity
while self.order[index] >= 0:
index = (index + 1) % self.capacity
self.order[index] = rank - 1

def pick(self, index):
return self.order[index]

def next(self, index):
return (index + 1) % self.capacity

0 comments on commit 0632551

Please sign in to comment.