Week6: Forward chaining and Backward Chaining
Outcome of this week is:
Aim: Implement expert systems with forward chaining and backward chaining. using Python
why is it called so:
either ways information available can be verified/ fact checked
F/w chaining: Data-driven (available data can have multiple goals)
B/w cahining: Goal-Driven ( A Goal is achievable or not from available data)
Forward and Backward Chaining- Theory
Forward Chaining: Forward chaining is a data-driven inference mechanism used in expert systems where reasoning begins with known facts and applies inference rules to derive new conclusions. The system continuously scans the rule base and fires rules whose conditions match the available facts. Newly inferred facts are added to the knowledge base until the desired goal is achieved or no more rules can be applied. It is suitable for prediction, monitoring, diagnosis, and control systems, where large datasets are available initially. Forward chaining is commonly used in production rule systems and artificial intelligence applications such as medical diagnosis and automated decision support.
Backward Chaining: Backward chaining is a goal-driven reasoning technique used in expert systems that starts from a hypothesis or goal and works backward to determine whether available facts support it. The system searches rules that can produce the required goal and recursively verifies whether the rule conditions are satisfied. If all sub-goals become true using known facts, the goal is confirmed. Backward chaining is efficient when the number of goals is limited because it avoids unnecessary rule evaluations. It is widely used in diagnostic systems, theorem proving, troubleshooting tools, and logic programming languages like Prolog.
# RULES
rules = {
("sun","planet"): "solar_system",
("earth","moon"): "planet",
("solar_system","galaxy"): "milky_way"
}
#F/W C
def forward(facts):
facts=set(facts)
changed=True
print("\nForward Chaining:")
while changed:
changed=False
for cond, result in rules.items():
if all(c in facts for c in cond)\
and result not in facts:
print("Rule Fired:",cond,"->",result)
facts.add(result)
changed=True
return facts
#B/W C
def backward(goal,facts):
print("Checking:",goal)
if goal in facts:
return True
for cond,result in rules.items():
if result==goal:
return all(
backward(c,facts)
for c in cond
)
return False
#FACTS
facts=input(
"Enter facts (comma separated): "
).split(",")
facts=[f.strip() for f in facts]
# F/W C EXEC
newfacts=forward(facts)
print("\nAll Facts:",newfacts)
#B/W C EXEC
goal=input("\nEnter Goal:")
if backward(goal,newfacts):
print("Goal TRUE")
else:
print("Goal FALSE")
# RULES
# IF conditions -> THEN conclusion
rules = [
(["marks>=75"], "distinction"),
(["marks>=50"], "pass"),
(["marks<50"], "fail"),
(["pass", "attendance_good"], "eligible_exam"),
(["distinction"], "scholarship")
]
#F/W CHAINING
def forward_chaining(facts, rules):
inferred = set(facts)
changed = True
print("\nForward Chaining Steps:")
while changed:
changed = False
for conditions, conclusion in rules:
if all(cond in inferred for cond in conditions) \
and conclusion not in inferred:
print(f"Rule Fired: {conditions} -> {conclusion}")
inferred.add(conclusion)
changed = True
return inferred
#B/W CHAINING
def backward_chaining(goal, facts, rules, visited=None):
if visited is None:
visited = set()
print("Checking Goal:", goal)
# already known fact
if goal in facts:
print(goal, "is a known fact")
return True
if goal in visited:
return False
visited.add(goal)
# search rule producing goal
for conditions, conclusion in rules:
if conclusion == goal:
print("Trying Rule:", conditions, "->", conclusion)
if all(backward_chaining(cond,
facts,
rules,
visited)
for cond in conditions):
print("Goal Achieved:", goal)
return True
return False
#INPUT
marks = int(input("Enter Student Marks : "))
attendance = input(
"Attendance Good? (yes/no) : ").lower()
facts = set()
# FACT CONVERSION
if marks >= 75:
facts.add("marks>=75")
if marks >= 50:
facts.add("marks>=50")
if marks < 50:
facts.add("marks<50")
if attendance == "yes":
facts.add("attendance_good")
#F/W CHAINING EXEC
fc_result = forward_chaining(facts, rules)
print("\nFinal Inferred Results:")
if "distinction" in fc_result:
print("Student Result : DISTINCTION")
elif "pass" in fc_result:
print("Student Result : PASS")
elif "fail" in fc_result:
print("Student Result : FAIL")
if "scholarship" in fc_result:
print("Scholarship Eligible")
if "eligible_exam" in fc_result:
print("Eligible for Final Exam")
#B/W CHAINING EXEC
goal = input(
"\nEnter Goal to Verify "
"(pass/fail/distinction/scholarship): "
)
if backward_chaining(goal, facts, rules):
print("\nGoal TRUE (Verified by Backward Chaining)")
else:
print("\nGoal FALSE (Cannot be Proven)")
# Rules: (conditions, conclusion)
rules = [
(["marks>=75"], "distinction"),
(["marks>=50"], "pass"),
(["marks<50"], "fail"),
(["pass", "attendance_good"], "eligible_exam"),
(["distinction"], "scholarship")
]
# Input
marks = int(input("Enter Student Marks: "))
attendance = input("Attendance Good? (yes/no): ").lower()
# Build facts
facts = set()
if marks >= 75: facts.add("marks>=75")
if marks >= 50: facts.add("marks>=50")
if marks < 50: facts.add("marks<50")
if attendance == "yes": facts.add("attendance_good")
# ── FORWARD CHAINING ──────────────────────────────────────
print("\nForward Chaining Steps:")
changed = True
while changed:
changed = False
for conditions, conclusion in rules:
if all(c in facts for c in conditions) and conclusion not in facts:
print(f" Rule Fired: {conditions} -> {conclusion}")
facts.add(conclusion)
changed = True
print("\nFinal Results:")
if "distinction" in facts: print("Student Result : DISTINCTION")
elif "pass" in facts: print("Student Result : PASS")
elif "fail" in facts: print("Student Result : FAIL")
if "scholarship" in facts: print("Scholarship Eligible")
if "eligible_exam" in facts: print("Eligible for Final Exam")
# ── BACKWARD CHAINING ─────────────────────────────────────
goal = input("\nEnter Goal to Verify (pass/fail/distinction/scholarship): ")
print(f"\nBackward Chaining Steps:")
stack = [goal] # goals to prove
visited = set()
proved = set(facts)
while stack:
current = stack[-1]
print(f" Checking: {current}")
if current in proved: # already known
print(f" '{current}' is known ✓")
stack.pop()
continue
if current in visited: # can't prove it
stack.pop()
continue
visited.add(current)
found_rule = False
for conditions, conclusion in rules:
if conclusion == current:
print(f" Trying Rule: {conditions} -> {conclusion}")
unproved = [c for c in conditions if c not in proved]
if unproved:
stack.extend(unproved) # push sub-goals
else:
proved.add(current) # all conditions met
found_rule = True
break
print()
if goal in proved:
print("Goal TRUE ✓ (Verified by Backward Chaining)")
else:
print("Goal FALSE ✗ (Cannot be Proven)")
rules = [
(["avg>=75"], "grade_A"),
(["avg>=60"], "grade_B"),
(["avg>=50"], "grade_C"),
(["avg<50"], "fail"),
(["grade_A"], "scholarship"),
(["attendance_low"], "detained"),
(["grade_B", "attendance_good"], "eligible_exam"),
(["grade_C", "attendance_good"], "eligible_exam")
]
def forward_chaining(facts, rules):
inferred = set(facts)
print("\nForward Chaining Steps:")
changed = True
while changed:
changed = False
for conditions, conclusion in rules:
if all(cond in inferred for cond in conditions) \
and conclusion not in inferred:
print("Rule Fired :", conditions,
"->", conclusion)
inferred.add(conclusion)
changed = True
return inferred
def backward_chaining(goal, facts,
rules, visited=None):
if visited is None:
visited = set()
print("Checking Goal :", goal)
if goal in facts:
print(goal, "is already known")
return True
if goal in visited:
return False
visited.add(goal)
for conditions, conclusion in rules:
if conclusion == goal:
print("Trying Rule:",
conditions, "->", conclusion)
if all(
backward_chaining(cond,
facts,
rules,
visited)
for cond in conditions):
print("Goal Achieved :", goal)
return True
return False
print("\nEnter Marks for 5 Subjects")
marks = []
for i in range(5):
m = int(input(f"Subject {i+1} Marks : "))
marks.append(m)
attendance = float(
input("\nAttendance Percentage : ")
)
average = sum(marks) / 5
print("\nAverage Marks =", average)
facts = set()
if average >= 75:
facts.add("avg>=75")
if average >= 60:
facts.add("avg>=60")
if average >= 50:
facts.add("avg>=50")
if average < 50:
facts.add("avg<50")
if attendance >= 75:
facts.add("attendance_good")
else:
facts.add("attendance_low")
results = forward_chaining(facts, rules)
print("\n------ FINAL RESULT ------")
if "detained" in results:
print("Student Status : DETAINED")
elif "grade_A" in results:
print("Grade : A")
elif "grade_B" in results:
print("Grade : B")
elif "grade_C" in results:
print("Grade : C")
elif "fail" in results:
print("Result : FAIL")
if "scholarship" in results:
print("Scholarship Eligible")
if "eligible_exam" in results:
print("Eligible for Final Examination")
goal = input(
"\nEnter Goal to Verify "
"(grade_A / scholarship / detained / fail): "
)
if backward_chaining(goal.strip(),
facts,
rules):
print("\nGoal TRUE")
else:
print("\nGoal FALSE")
different data set and verification
Forward Chaining:
Q1: What type of reasoning is forward chaining?
A: Data-driven reasoning.
Q2: Where does forward chaining start?
A: From known facts.
Q3: When does forward chaining stop?
A: When no new rule can be fired or goal is reached.
Q4: One application of forward chaining?
A: Monitoring or prediction systems.
Q5: What happens when a rule fires?
A: New facts are added to the knowledge base.
Backward Chaining:
Q1: What type of reasoning is backward chaining?
A: Goal-driven reasoning.
Q2: Where does backward chaining begin?
A: From the goal or hypothesis.
Q3: Which language commonly uses backward chaining?
A: Prolog.
Q4: When is backward chaining efficient?
A: When the number of goals is small.
Q5: What are subgoals?
A: Conditions required to prove a rule.