Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/classifier_integration_ex.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
fraud_detector = pr.LogicIntegratedClassifier(
model,
class_names,
identifier="fraud_detector",
model_name="fraud_detector",
interface_options=interface_options
)

Expand Down
622 changes: 622 additions & 0 deletions examples/image_classifier_example/classifier.ipynb

Large diffs are not rendered by default.

83 changes: 83 additions & 0 deletions examples/image_classifier_two/image_classifier_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
from transformers import AutoImageProcessor, AutoModelForImageClassification
from PIL import Image
import torch
import pyreason as pr
import networkx as nx
import torch.nn.functional as F

# Step 1: Load a pre-trained model and image processor from Hugging Face
model_name = "google/vit-base-patch16-224" # Vision Transformer model
processor = AutoImageProcessor.from_pretrained(model_name)
model = AutoModelForImageClassification.from_pretrained(model_name)

# Step 2: Load and preprocess an image
image_path = "/Users/coltonpayne/pyreason/examples/image_classifier_two/goldfish.jpeg"
image = Image.open(image_path)

inputs = processor(images=image, return_tensors="pt")

# Step 3: Run the image through the model
with torch.no_grad():
outputs = model(**inputs)

# Step 4: Get the logits and apply softmax
logits = outputs.logits
probs = F.softmax(logits, dim=-1)

# --- NEW SECTION: Restrict predictions to a subset of labels ---
# Define your allowed labels
allowed_labels = ['goldfish', 'tiger shark', 'hammerhead', 'great white shark', 'tench']

# Get the index-to-label mapping from the model config
id2label = model.config.id2label

# Get the indices of the allowed labels
# Get the indices of the allowed labels, stripping everything after the comma
allowed_indices = [
i for i, label in id2label.items()
if label.split(",")[0].strip().lower() in [name.lower() for name in allowed_labels]
]


# Filter and re-normalize probabilities
filtered_probs = torch.zeros_like(probs)
filtered_probs[0, allowed_indices] = probs[0, allowed_indices]
filtered_probs = filtered_probs / filtered_probs.sum()

# Get top prediction among allowed labels
top_idx = filtered_probs.argmax(-1).item()
top_label = id2label[top_idx].split(",")[0]
top_prob = filtered_probs[0, top_idx].item()

print(f"\nTop prediction (filtered): {top_label} ({top_prob:.4f})")

# Optional: print top N from the filtered subset
top_probs, top_indices = filtered_probs.topk(5)
print("\nTop predictions from allowed subset:")
for prob, idx in zip(top_probs[0], top_indices[0]):
label = id2label[idx.item()].split(",")[0]
print(f"{label}: {prob.item():.4f}")


interface_options = pr.ModelInterfaceOptions(
threshold=0.5, # Only process probabilities above 0.5
set_lower_bound=True, # For high confidence, adjust the lower bound.
set_upper_bound=False, # Keep the upper bound unchanged.
snap_value=1.0 # Use 1.0 as the snap value.
)

fish_classifier = pr.LogicIntegratedClassifier(
model,
allowed_labels,
model_name="fish_classifier",
interface_options=interface_options
)

logits, probabilities, classifier_facts = fish_classifier(image)

print("=== Fish Classifier Output ===")
print("Logits:", logits)
print("Probabilities:", probabilities)
print("\nGenerated Classifier Facts:")
for fact in classifier_facts:
print(fact)
Binary file added examples/image_classifier_two/images/fish_1.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/image_classifier_two/images/fish_2.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/image_classifier_two/images/shark_1.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/image_classifier_two/images/shark_2.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/image_classifier_two/images/shark_3.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
80 changes: 80 additions & 0 deletions football_project/football_classes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import enum
import math

# This graph will determine which free agents a team can sign based on their available cap space
# and which players they should sign based on their needs and other player factors

class LeagueRules(enum.Enum): # Fixed the base class
POSTION_LIST = ["QB", "RB", "WR", "TE"]
MIN_PLAYER_AT_POSITION = {
"QB": 1,
"RB": 1,
"WR": 2,
"TE": 1,
}
SALARY_CAP = 2000000

class FootballPlayer:
def __init__(self, name, position, expected_salary, madden_rating, available=True):
self.name = name
self.position = position
self.expected_salary = expected_salary
self.madden_rating = madden_rating
self.available = available
self.player_value = (self.madden_rating / self.expected_salary) * 100000

def get_availability(self):
return self.available

class FootballTeam:
def __init__(self, team_name):
self.team_name = team_name
self.roster = {}
for position in LeagueRules.POSTION_LIST.value:
self.roster[position] = []
self.cap_space = LeagueRules.SALARY_CAP.value

def can_sign_player(self, player):
if player.expected_salary <= self.cap_space and player.get_availability():
return True
return False

# A team wants to sign a player if the player can provide more value than the lowest value player at thier position
def check_if_team_wants_players(self, player):
lowest_rostered_value_at_pos = self.get_lowest_value_at_position(player.position)
if player.player_value > lowest_rostered_value_at_pos:
# print(f"Team {self.team_name} wants player {player.name} with value {player.player_value}. Lowest value is {lowest_rostered_value_at_pos}.")
return True
return False

def get_lowest_value_at_position(self, position):
min_value = math.inf
for player in self.roster[position]:
if player.player_value < min_value:
min_value = player.player_value

return min_value

def sign_player(self, player):
if self.can_sign_player(player):
#self.roster.append(player)
self.roster[player.position].append(player)
self.cap_space -= player.expected_salary
player.available = False
return True
return False

def get_available_players(self):
return [player for player in self.roster if player.get_availability()]

def get_cap_space(self):
return self.cap_space

def get_num_player_needed(self, position):
current_qbs = [player for player in self.roster[position]]
num_players_needed = LeagueRules.MIN_PLAYER_AT_POSITION.value[position] - len(current_qbs)
return num_players_needed

def get_remaining_cap_space(self):
total_salary = sum(player.expected_salary for player in self.roster)
return self.cap_space - total_salary
221 changes: 221 additions & 0 deletions football_project/player_signings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
import numba
import pyreason as pr
import networkx as nx
import football_classes as fc
import random
from pprint import pprint
import matplotlib.pyplot as plt # type: ignore

# Generates random names
import names

def generate_random_player_at_position(position):
full_name = names.get_full_name()
name_with_underscore = full_name.replace(" ", "_")
return fc.FootballPlayer(
name=name_with_underscore,
position=position,
expected_salary=random.randint(100000, 500000),
madden_rating=random.randint(60, 99),
)

def add_rostered_fact(team, player):
fact_string = f"rostered({team.team_name} , {player.name})"
pr.add_fact(pr.Fact(fact_string, 'rostered_fact', 0, 1))

def add_not_rostered_fact(team, player):
fact_string = f"~rostered({team.team_name} , {player.name})"
pr.add_fact(pr.Fact(fact_string, 'rostered_fact', 0, 1))

def try_to_sign_player(team, player):
if team.can_sign_player(player):
team.sign_player(player)
add_rostered_fact(team, player)
print(f"{team.team_name} signed {player.name} for ${player.expected_salary}")
else:
add_not_rostered_fact(team, player)

# Operating at timestep 1
def add_interested_fact(team, player):
fact_string = f"interested({team.team_name} , {player.name})"
pr.add_fact(pr.Fact(fact_string, 'interested_fact', 0, 1))

def add_not_interested_fact(team, player):
fact_string = f"~interested({team.team_name} , {player.name})"
pr.add_fact(pr.Fact(fact_string, 'interested_fact', 0, 1))

def determine_team_interest():
for team in team_list:
for player in all_player_list:
if team.check_if_team_wants_players(player):
add_interested_fact(team, player)
else:
add_not_interested_fact(team, player)

def simulate_draft():
# print("Available Players:")
# for player in all_players:
# print(f"Name: {player.name}, Position: {player.position}, "
# f"Expected Salary: ${player.expected_salary:,}, Madden Rating: {player.madden_rating}")
for team in team_list:
# Loop through the available players and try to sign them
for player in qb_list:
if team.get_num_player_needed("QB") > 0:
try_to_sign_player(team, player)
else:
add_not_rostered_fact(team, player)
for player in rb_list:
if team.get_num_player_needed("RB") > 0:
try_to_sign_player(team, player)
else:
add_not_rostered_fact(team, player)
for player in wr_list:
if team.get_num_player_needed("WR") > 0:
try_to_sign_player(team, player)
else:
add_not_rostered_fact(team, player)
for player in te_list:
if team.get_num_player_needed("TE") > 0:
try_to_sign_player(team, player)
else:
add_not_rostered_fact(team, player)

# Print the final rosters and cap space for each team
print("\nFinal Rosters and Cap Space:")
for team in team_list:
print(f"\n{team.team_name} Roster:")
for position, players in team.roster.items():
for player in players:
print(f" Name: {player.name}, Position: {player.position}, Value: {player.player_value}")
print(f"Cap Space Remaining: ${team.get_cap_space():,}")


qb_list = []
rb_list = []
wr_list = []
te_list = []
all_player_list = []

for val in range(20):
qb_list.append(generate_random_player_at_position("QB"))
rb_list.append(generate_random_player_at_position("RB"))
wr_list.append(generate_random_player_at_position("WR"))
te_list.append(generate_random_player_at_position("TE"))

all_player_list.extend(qb_list)
all_player_list.extend(rb_list)
all_player_list.extend(wr_list)
all_player_list.extend(te_list)

team_list = []
team_list.append(fc.FootballTeam("Pittsburgh_Steelers"))
team_list.append(fc.FootballTeam("Baltamore_Ravens"))
team_list.append(fc.FootballTeam("Dallas_Cowboys"))
team_list.append(fc.FootballTeam("Chicago_Bears"))



# Create a Directed graph
g = nx.DiGraph()

for player in all_player_list:
g.add_node(player.name, name=player.name, position=player.position, expected_salary=player.expected_salary, madden_rating=player.madden_rating, player_value=player.player_value)
for team in team_list:
g.add_node(team.team_name)

# Make a picture of the graph
# nx.draw(g, with_labels=True)
# plt.savefig("football_graph.png")
# plt.show()

pr.settings.verbose = True # Print info to screen
pr.settings.atom_trace = True # Print the trace of the atoms

# Load all the files into pyreason
pr.load_graph(g)


@numba.njit
def demanded_player_annotation_fn(annotations, weights):
"""
Calculate the value of a player based on their attributes.
"""
# Calculate the value based on the weights
# print("Annotations: ", annotations)
# print("Annotations[0]: ", annotations[0])
num_interested_teams = len(annotations[0])
print("Interested Teams: ", num_interested_teams)
if num_interested_teams > 3:
upper_bound = 1
lower_bound = 1
else:
upper_bound = 0
lower_bound = 0
return lower_bound, upper_bound

pr.add_annotation_function(demanded_player_annotation_fn)

# These functions add facts about the players based on how they are drafted and the teams that want them
simulate_draft()
determine_team_interest()

# Rule to check if a player is a free agent
pr.add_rule(pr.Rule('rostered_player(x) <-1 rostered(y, x)', 'rostered_player_rule'))
pr.add_rule(pr.Rule('free_agent(x) <-1 ~rostered(y,x)', 'free_agent_rule'))
pr.add_rule(pr.Rule('make_offer(y,x) <-1 free_agent(x), interested(y,x)', 'make_offer_rule'))
pr.add_rule(pr.Rule('demanded_player(x) : demanded_player_annotation_fn <-1 make_offer(a,x)', 'demanded_player(x)'))
pr.add_rule(pr.Rule('highly_demanded_player(x) <-1 demanded_player(x): [1,1]', 'highly_demanded_player_rule'))

#pr.add_rule(pr.Rule('team_interested_in_player(x, y) <-1 '))

interpretation = pr.reason(timesteps=4)
interpretation_dict = interpretation.get_dict()
# print("Interpretation Dictionary:")
# pprint(interpretation_dict)

# Display the changes in the interpretation for each timestep
print("========================== Rostered Players ==========================")
rostered_player_df = pr.filter_and_sort_nodes(interpretation, ['rostered_player'])
for t, df in enumerate(rostered_player_df):
print(f'TIMESTEP - {t}')
print(df)
print()

print("========================== Free Agents ==========================")
free_agent_df = pr.filter_and_sort_nodes(interpretation, ['free_agent'])
for t, df in enumerate(free_agent_df):
print(f'TIMESTEP - {t}')
print(df)
print()


print("========================== Team offers ==========================")
team_offer_df = pr.filter_and_sort_edges(interpretation, ['make_offer'])
for t, df in enumerate(team_offer_df):
print(f'TIMESTEP - {t}')
print(df)
print()

print("========================== Demanded Player ==========================")
team_offer_df = pr.filter_and_sort_nodes(interpretation, ['demanded_player'])
for t, df in enumerate(team_offer_df):
print(f'TIMESTEP - {t}')
print(df)
print()

print("========================== Hot Commodities ==========================")
hot_commodity_df = pr.filter_and_sort_nodes(interpretation, ['highly_demanded_player'])
for t, df in enumerate(hot_commodity_df):
print(f'TIMESTEP - {t}')
print(df)
for index, row in df.iterrows():
node_name = row['component']
player_value = g.nodes[node_name]["player_value"]
madden_rating = g.nodes[node_name]["madden_rating"]
expected_salary = g.nodes[node_name]["expected_salary"]
print(f"Node: {node_name}, Salary: {expected_salary}, Madden Rating: {madden_rating}, Value: {player_value}")


# Iterate over the "component" column in hot_commodity_df and print everything we know about the corresponding node

pr.save_rule_trace(interpretation)
2 changes: 1 addition & 1 deletion pyreason/.cache_status.yaml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
initialized: false
initialized: true
Loading