Skip to content

Commit

Permalink
Add option to check if a groupoid is asymptotic complete.
Browse files Browse the repository at this point in the history
  • Loading branch information
nick-falco committed Aug 17, 2024
1 parent eed7e4a commit 32c21cc
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 3 deletions.
2 changes: 1 addition & 1 deletion eat/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v2.1.3
v2.1.4
53 changes: 53 additions & 0 deletions eat/core/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,59 @@ def __str__(self):
[str(cell) for cell in row])
for row in self.data])

def is_asymptotic_complete(self, probabilities, term_variables, limit=700):
if not probabilities:
raise ValueError("You must specify probability values to use")
elif len(probabilities) != self.size:
raise ValueError("The number of probability values must match the "
"size of the groupoid.")
elif sum(probabilities) != 1:
raise ValueError("Probabilies must add to one.")

def get_operations_resolving_to_value(output_val):
operation_pairs = []
for row_idx, row in enumerate(self.data):
for col_idx, _ in enumerate(row):
if self.data[row_idx][col_idx] == output_val:
operation_pairs.append([row_idx, col_idx])
return operation_pairs

def compute_ac_table(t_H, probs, limit=700):
print("Computing AC table")
table = []
i_H = None
while len(table) < limit:
if not i_H or 1 - i_H < math.pow(10, -6):
t_H_plus_1 = (t_H * t_H) + len(term_variables)
i_H = (t_H * t_H) / t_H_plus_1
else:
t_H_plus_1 = t_H
# add computed probabilities
table.append([])
for input_value in range(self.size):
if input_value < self.size - 1:
# compute series summing over all probabilities
operation_pairs = \
get_operations_resolving_to_value(input_value)
series = 0
for operation_pair in operation_pairs:
series += (probs[operation_pair[0]] *
probs[operation_pair[1]])
# use series to compute b_H_plus_1
b_H_plus_1 = (i_H * series) + \
((1 - i_H) * probabilities[input_value])
else:
b_H_plus_1 = 1 - sum(table[-1])
table[-1].append(b_H_plus_1) # add each probability value
probs = table[-1] # Update probs for the next iteration
t_H = t_H_plus_1 # Update t_H for the next iteration
return table

table = compute_ac_table(len(term_variables),
probabilities,
limit=limit)
return table

def set_value(self, x, y, value):
"""
Set groupoid value at index (x, y)
Expand Down
24 changes: 24 additions & 0 deletions eat/core/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,27 @@ def print_execution_results_summary(execution_results, run_count,
f"{result['term_length']}")
print(f"Average search time: {avg_time} sec")
print(f"Average term length: {int(avg_term_length)}")


def print_ac_table(table_output):
# Calculate the maximum width for each column
col_widths = [max(len(f"{v:.6f}") for v in col)
for col in zip(*table_output)]
header_widths = [max(len(f"B{i}"), col_width)
for i, col_width in enumerate(col_widths)]

# Calculate the width needed for the row index column
index_width = max(len(str(len(table_output))), len("H"))

# Print the header
header = "H".ljust(index_width) + " " + " ".join(
[f"B{i}".ljust(header_width)
for i, header_width in enumerate(header_widths)])
print(header)

# Print each row
for i, row in enumerate(table_output):
row_str = f"{i+1}".ljust(index_width) + " " + " ".join([
f"{v:.6f}".ljust(header_width)
for v, header_width in zip(row, header_widths)])
print(row_str)
25 changes: 23 additions & 2 deletions eat/runeat.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
from eat.beam_algorithm.beam import BeamEnumerationAlgorithm
from eat.deep_drilling_algorithm.dda import DeepDrillingAlgorithm
from eat.core.components import Groupoid, TermOperation
from eat.core.utilities import print_execution_results_summary
from eat.utilities.argparse_types import non_negative_integer, restricted_float
from eat.core.utilities import print_execution_results_summary, \
print_ac_table
from eat.utilities.argparse_types import non_negative_integer, \
positive_integer, restricted_float


def parse_arguments():
Expand Down Expand Up @@ -102,6 +104,17 @@ def parse_arguments():
help=("Whether to include validity array in "
"verbose log output (default=False)"),
action='store_true')
ac_group = parser.add_argument_group(
'Options for asymptotic complete')
ac_group.add_argument('-ac', '--asymptotic-complete',
help=("Check if groupoid is asymptotic complete."),
action='store_true')
ac_group.add_argument('-acp', '--ac-probabilities',
help=("Probability values to use at height 1."),
nargs='+', type=restricted_float)
ac_group.add_argument('-th', '--table-height',
help=("Print a table of this height."),
type=positive_integer, default=700)

return parser.parse_args()

Expand Down Expand Up @@ -129,6 +142,14 @@ def main():
to.target = to.get_filled_target_array(to.target,
args.target_free_count)

# Run AC check and return table
if args.asymptotic_complete is True:
ac_table = grp.is_asymptotic_complete(args.ac_probabilities,
args.term_variables,
limit=args.table_height)
print_ac_table(ac_table)
return

mtgm = args.male_term_generation_method

verbose = args.verbose
Expand Down
8 changes: 8 additions & 0 deletions eat/utilities/argparse_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ def restricted_float(x):
def non_negative_integer(value):
ivalue = int(value)
if ivalue < 0:
raise argparse.ArgumentTypeError(
"{} is not a non negative int literal".format(value))
return ivalue


def positive_integer(value):
ivalue = int(value)
if ivalue <= 0:
raise argparse.ArgumentTypeError(
"{} is not a positive int literal".format(value))
return ivalue

0 comments on commit 32c21cc

Please sign in to comment.