Daily Rambam · Techie Talmid · Standard
Mishneh Torah, Testimony 13
This is going to be a fantastic deep dive! We're going to take the venerable laws of witness disqualification from Mishneh Torah, Testimony Chapter 13, and model them using the elegant logic of systems thinking. Think of it as refactoring ancient code for maximum clarity and efficiency. Get ready for some serious algorithm analysis!
Problem Statement – The "Bug Report" in the Sugya
Our core "bug report" in Mishneh Torah, Testimony Chapter 13, revolves around a seemingly simple rule: relatives are disqualified from testifying. But as we start to unpack this, we find a complex web of "dependencies" and "privileges" that aren't immediately obvious from a high-level scan. The system is designed to prevent bias, but the "edge cases" and "inheritance" of disqualification can lead to unexpected outcomes if not modeled precisely.
Specifically, the initial "specification" (Scriptural Law) is quite narrow, focusing only on direct paternal lines. The "system administrators" (the Rabbis) then introduce significant "patches" and "enhancements" (Rabbinic decrees) that expand the disqualification to a much wider set of relationships. The challenge lies in understanding the rules of propagation for these disqualifications, particularly how they cascade through generations and across different types of familial connections (paternal, maternal, marital).
The "documentation" (the text itself) describes these rules in a narrative, almost procedural way, which is great for understanding the intent, but less ideal for building a robust, predictable "witness eligibility checker" system. We need to move from a "user manual" to an "API specification."
The "bug" isn't that the system is broken, but that its internal logic isn't explicitly defined in a way that allows for easy, deterministic computation. Without a clear algorithmic representation, it's easy to misinterpret the scope of disqualification, especially when dealing with multiple layers of relationships or indirect connections.
For instance, the text states: "Whenever a person is disqualified from testifying on behalf of a woman, he is also disqualified from testifying on behalf of her husband, for a husband is considered like his wife." This is a crucial rule for understanding how disqualifications propagate through marital unions. Similarly, the distinction between Scriptural disqualification (paternal lines) and Rabbinic disqualification (maternal, marital) is a key "feature flag" that needs to be handled.
The ultimate goal of this refactoring is to build a computational model that can accurately predict witness eligibility based on any given relationship matrix, ensuring we don't fall prey to the "false positives" (disqualifying valid witnesses) or "false negatives" (accepting biased witnesses) that a less rigorous system might produce. We're aiming for a system with O(1) complexity for eligibility checks, once the relationship graph is built!
Full Experience in the App
Listen. Chat. Go deeper.
Audio playback, interactive chevruta, Hebrew tools, and every daily learning track — only in Derekh Learning.
Text Snapshot
Here are the key lines that form the backbone of our analysis, with anchors for precise reference:
- [1] "Relatives are disqualified as witnesses according to Scriptural Law, as implied by Deuteronomy 24:16: 'Fathers shall not die because of sons.'"
- [2] "According to the Oral Tradition, the verse is interpreted as meaning that included in this prohibition is that fathers should not die because of the testimony of sons, nor should sons die because of the testimony of fathers."
- [3] "According to Scriptural Law, only paternal relatives are disqualified - i.e., a father with his sons and grandsons, paternal brothers with each other, and the sons of paternal brothers with each other."
- [4] "Maternal relatives or people related by marriage are disqualified only by Rabbinic decree."
- [5] "Even two twin brothers who convert may testify on each others behalf."
- [6] "Brothers - whether maternal brothers or paternal - are considered as one degree removed."
- [7] "Their sons are considered as two degrees removed."
- [8] "And their grandsons are three degrees removed."
- [9] "A person who is three degrees removed may testify on behalf of one who is one degree removed."
- [10] "Needless to say, one who is three degrees removed may testify on behalf of one who is two degrees removed."
- [11] "But two who are both two degrees removed, and needless to say, one who is two degrees removed and one who is one degree removed are both disqualified from testifying."
- [12] "A father and his son are considered as one degree removed."
- [13] "Therefore a father is disqualified from testifying with his grandson."
- [14] "With his great-grandson, i.e., the fourth generation, he is acceptable, for he is of the first degree and the great-grandson, three degrees, removed."
- [15] "Similar laws apply with regard to women relatives."
- [16] "Two sisters or a brother and a sister - whether paternally or maternally related - are considered as one degree removed."
- [17] "Their children whether male or female are considered as two degrees removed and their grandchildren - including the sons of their sons and the daughters of their daughters - are considered as three degrees removed."
- [18] "Just as we count the degrees descendants are removed for males - one degree, two degrees, and three degrees - so, too, we count the degrees for females."
- [19] "Whenever a person is disqualified from testifying on behalf of a woman, he is also disqualified from testifying on behalf of her husband, for a husband is considered like his wife."
- [20] "Conversely, whenever a person is disqualified from testifying on behalf of a man, he is also disqualified from testifying on behalf of his wife, for a wife is considered like her husband."
- [21] "Whenever two women are removed by second degrees, their husbands may testify on behalf of each other."
- [22] "If, however, the women are one degree removed, e.g., a man married a woman, and a colleague married her daughter, the two men may not testify on each other's behalf."
- [23] "Similarly, the husbands of two sisters are disqualified with regard to each other and are considered as one degree removed."
- [24] "Similarly, a person should not testify on behalf of the son of his wife's sister, nor on behalf of the husband of the daughter of his wife's sister."
- [25] "He may, however, testify on behalf of the son of the husband of his wife's sister who was born to that person from another wife."
- [26] "Whenever a witness is disqualified from testifying on behalf of a colleague because he is married to the witness' relative, the witness may testify on behalf of the other relatives of that colleague, e.g., his son and his brother."
- [27] "Similarly, whenever a witness is disqualified from testifying on behalf of a woman because she is married to the witness' relative, the witness may testify on behalf of her other relatives, e.g., her son and her brother."
- [28] "The father of a bride and the father of a groom may testify on behalf of each other."
- [29] "A person's paternal brother may testify on behalf of that person's maternal brother and the maternal brother may testify on behalf of the paternal brother, for they have no connection whatsoever."
- [30] "Rachel married Joseph and bore him a son Reuven. Joseph had a son, Menashe, from another wife. Joseph died and Rachel married Shimon and bore him Judah. Menashe and Judah may testify on each other's behalf."
- [31] "A man and his wife are considered as being removed by one degree."
- [32] "Hence a husband may not testify on behalf of his wife's son, the wife of his wife's son, his wife's daughter, the husband of his wife's daughter, his wife's father, his wife's mother, the husband of his wife's mother, nor the wife of his wife's father."
- [33] "When a person has consecrated a woman, although the marriage bond has not been consummated, with regard to testimony, it is as if she is fully married."
- [34] "To whom does the above apply? To the woman he consecrated herself; he may not testify on her behalf."
- [35] "If, however, he testifies on behalf of the relatives of the woman he consecrated, e.g., her sister's husband, her son or daughter, or the like, we do not disqualify him until he marries her."
- [36] "The Torah did not disqualify the testimony of relatives because we assume that they love each other, for a relative may not testify neither on his relative's behalf or against his interests. Instead, this is a Scriptural decree."
- [37] "For this reason people who love each other or who hate each other are acceptable as witnesses even though they are not acceptable as judges. For the Scriptural decree disqualifies only relatives as witnesses."
And from the commentary:
- [Ohr Sameach] "The Rabbi in the Nodah B'Yehuda... wrote that I would even say that from the verse... all his words, and he thought we equate closeness of forbidden relations with closeness that disqualifies testimony. And it is not so, for it is permitted for a person to marry his brother's daughter, and he is disqualified from testifying according to Torah Law, and so too his son's daughter is a forbidden relation, but may testify for him, as with Mar bar Rav Ashi. And similarly, concerning marital relations, we certainly do not equate forbidden relations with testimony. Rather, the Gemara learns that a woman is like her husband from the verse of 'his uncle' which is his father's brother according to the Torah, and 'his aunt' is written 'and Amram took Yocheved his aunt, who was the daughter of Levi' - here his aunt is his father's sister. And here it is written 'Do not approach your aunt, she is your father's sister.' And it is also written 'A man who lies with his aunt has exposed his uncle's nakedness' - behold the woman is called his aunt like the husband. We see that the relationship is attributed equally by the same name to the uncle and his wife. Therefore, we learn concerning the closeness of Torah Law that sons are to each other, so too their wives. But to learn from this that it is permitted from the Torah for his mother's brother's wife, that she is not like his wife - this is nonsense. For we do not learn from forbidden relations what the Torah has forbidden, but from the wording that the Torah uses, we learn that a woman is like her husband. And therefore the Gemara learns about his stepson's wife, even though concerning forbidden relations one is permitted with his stepson's wife and she is not like his wife, and his mother's sister is forbidden by the Torah, and not because she is his aunt, and it is simple. And far be it from us to join any side to permit from this. And although from the words of the Me'or it seems somewhat that it depends on forbidden relations, see in the Milchamot that he clarified well, read carefully there."
- [Steinsaltz 1:1] "Disqualified for testimony."
- [Steinsaltz 1:2] "From the tradition."
- [Steinsaltz 1:3] "On behalf of sons."
- [Steinsaltz 1:4] "And brothers from the father."
- [Steinsaltz 1:5] "And their sons with each other."
- [Steinsaltz 1:6] "And it is not necessary to say the uncle with his brother's son."
- [Steinsaltz 1:7] "Other relatives from the mother."
Flow Model – The Decision Tree of Disqualification
Let's model the disqualification rules as a decision tree. This helps visualize the conditional logic. We'll start with a potential witness (W) and a person they might testify for (P).
Root Node: Is Witness (W) disqualified from testifying for Person (P)?
Branch 1: Is the relationship between W and P Scripturally disqualified?
- Condition: Are W and P related paternally?
- Yes:
- Check Degree:
- Degree 1 (Parent-Child, Siblings): Disqualified. (Mishneh Torah, Testimony 13:1:3, 13:1:6, 13:1:12)
- Degree 2 (Grandchild, Nephew/Niece via Brother): Disqualified. (Mishneh Torah, Testimony 13:1:3, 13:1:7)
- Degree 3 (Great-Grandchild, Grand-Nephew/Niece via Brother): Not Scripturally disqualified. (Mishneh Torah, Testimony 13:1:8, 13:1:14)
- Exception: If the disqualification is also Rabbinically mandated, then apply Rabbinic rules. (See Branch 2)
- Check Degree:
- No (Not purely paternal, or no direct paternal line): Proceed to Branch 2.
- Yes:
- Condition: Are W and P related paternally?
Branch 2: Is the relationship between W and P Rabbinically disqualified?
- Condition: Are W and P related maternally OR by marriage?
Yes:
- Check Degree (Maternal):
- Degree 1 (Maternal Siblings): Disqualified. (Mishneh Torah, Testimony 13:1:6)
- Degree 2 (Children of Maternal Siblings): Disqualified. (Mishneh Torah, Testimony 13:1:7)
- Degree 3 (Grandchildren of Maternal Siblings): Not Rabbinically disqualified. (Mishneh Torah, Testimony 13:1:8, 13:1:17)
- Check Degree (Marital - W married to P's relative, or P married to W's relative):
- Rule 1 (W married to P's relative):
- Sub-Rule 1.1: If W is disqualified from testifying for P's spouse (because P's spouse is W's relative), then W is also disqualified for P. (Mishneh Torah, Testimony 13:1:19, 13:1:20)
- Sub-Rule 1.2: If W is disqualified from testifying for P because P is married to W's relative (e.g., P is W's sister's husband), then W is not disqualified for P's other relatives (e.g., P's son, P's brother). (Mishneh Torah, Testimony 13:1:26, 13:1:27)
- Sub-Rule 1.3: Specific Case: Husbands of two sisters are disqualified regarding each other (Degree 1 marital). (Mishneh Torah, Testimony 13:1:23)
- Sub-Rule 1.4: Specific Case: Father of bride and father of groom can testify for each other. (Mishneh Torah, Testimony 13:1:28)
- Sub-Rule 1.5: Specific Case: If W is married to X, and X is married to Y's daughter, W is disqualified for Y. (Mishneh Torah, Testimony 13:1:22)
- Sub-Rule 1.6: Specific Case: W cannot testify for son of his wife's sister, nor husband of his wife's daughter. (Mishneh Torah, Testimony 13:1:24)
- Sub-Rule 1.7: Exception to 1.6: W can testify for son of his wife's sister's husband, if born from another wife. (Mishneh Torah, Testimony 13:1:25)
- Sub-Rule 1.8: Consecration: Treated as marriage for disqualification purposes. (Mishneh Torah, Testimony 13:1:33, 13:1:34)
- Exception to 1.8: W is not disqualified for consecrated woman's relatives until marriage is consummated. (Mishneh Torah, Testimony 13:1:35)
- Rule 2 (P married to W's relative):
- This is essentially the inverse of Rule 1, and the disqualification propagates similarly. (Mishneh Torah, Testimony 13:1:19, 13:1:20)
- Rule 1 (W married to P's relative):
- Rule 3 (General Degree Calculation for Descendants):
- A person and their sibling are Degree 1. (Mishneh Torah, Testimony 13:1:6)
- Their children are Degree 2. (Mishneh Torah, Testimony 13:1:7)
- Their grandchildren are Degree 3. (Mishneh Torah, Testimony 13:1:8)
- This applies equally to male and female lines. (Mishneh Torah, Testimony 13:1:15, 13:1:18)
- Rule 4 (Cross-Relationship Test):
- If W is disqualified for P, and P is disqualified for W (mutual disqualification), then they are both disqualified. (This is implied by the symmetry of testimony disqualification).
- If W and P are both Degree 2 removed from a common ancestor (e.g., cousins), they are disqualified. (Mishneh Torah, Testimony 13:1:11)
- If W is Degree 2 and P is Degree 1, they are disqualified. (Mishneh Torah, Testimony 13:1:11)
- If W is Degree 3 and P is Degree 1 or 2, they are not disqualified. (Mishneh Torah, Testimony 13:1:9, 13:1:10)
- Check Degree (Maternal):
No (Not related maternally or by marriage):
- Check if they are converts: Converts are not considered relatives. (Mishneh Torah, Testimony 13:1:5)
- Yes: Not disqualified based on relationship. Proceed to check other disqualification grounds (not covered in this sugya).
- No: Not disqualified based on relationship. Proceed to check other disqualification grounds.
- Check if they are converts: Converts are not considered relatives. (Mishneh Torah, Testimony 13:1:5)
- Condition: Are W and P related maternally OR by marriage?
Final Output: Disqualified (Yes/No)
This tree structure highlights the branching logic based on the type of relationship (Scriptural vs. Rabbinic) and then the degree of removal. The marital relationship rules add a particularly complex layer of conditional logic.
Two Implementations – Algorithm A vs. Algorithm B
Let's think about how different Rishonim (early commentators) and Acharonim (later commentators) might have conceptualized and implemented these rules. We'll model this as two algorithmic approaches: Algorithm A, representing a more literal, generation-by-generation approach, and Algorithm B, a more abstract, graph-based approach that leverages relationship attributes.
Algorithm A: The Generational Descent Tracker (A Rishonim-like Approach)
This approach focuses on tracing direct lines of descent and ascendance, meticulously counting generations. It's like a recursive function that walks up and down family trees.
Core Data Structure:
Personobject: Containsname,father,mother,children(list),siblings(list),spouse.Relationshipobject: Stores the type of relationship (e.g., "paternal_father", "maternal_brother", "wife_of_son").
Algorithm Logic (Conceptual Pseudocode):
# Initialize a global database of all persons and their relationships
def is_disqualified_algorithm_A(witness_id, person_id):
# Step 1: Check for direct Scriptural disqualification (Paternal)
if check_scriptural_disqualification_A(witness_id, person_id):
return True
# Step 2: Check for Rabbinic disqualification (Maternal, Marital)
if check_rabbinic_disqualification_A(witness_id, person_id):
return True
return False
def check_scriptural_disqualification_A(w_id, p_id):
# This function primarily checks paternal lines based on degrees.
# It involves tracing upwards to a common paternal ancestor.
# Function to trace paternal lineage upwards
def get_paternal_ancestors(person_id):
ancestors = []
current = person_id
while person_exists(current) and get_father(current) is not None:
ancestors.append(get_father(current))
current = get_father(current)
return ancestors
# Function to trace paternal descendants downwards
def get_paternal_descendants(person_id):
descendants = []
queue = [person_id]
while queue:
current = queue.pop(0)
for child_id in get_children(current):
# Only consider paternal children for this specific check
if is_paternal_child(child_id, current): # Need a way to distinguish paternal vs maternal children
descendants.append(child_id)
queue.append(child_id)
return descendants
# Degree Calculation Helper (simplified for paternal)
def calculate_paternal_degree(ancestor_id, descendant_id):
if ancestor_id == descendant_id: return 0
if get_father(descendant_id) == ancestor_id: return 1 # Direct son
if get_father(get_father(descendant_id)) == ancestor_id: return 2 # Grandson
# ... and so on, could be recursive or iterative up to 3 degrees for disqualification
# More robust: Trace up from descendant to find ancestor and count steps
path = []
current = descendant_id
while current is not None:
path.append(current)
if current == ancestor_id:
return len(path) - 1 # Degree is number of steps
current = get_father(current)
return float('inf') # Not a paternal descendant
# Check direct father-son, father-grandson (paternal)
w_father = get_father(w_id)
w_grandfather = get_father(w_father) if w_father else None
w_greatgrandfather = get_father(w_grandfather) if w_grandfather else None
p_father = get_father(p_id)
p_grandfather = get_father(p_father) if p_father else None
p_greatgrandfather = get_father(p_grandfather) if p_grandfather else None
# Case: Father and Son (Degree 1)
if w_father == p_id or p_father == w_id: return True # Disqualified
# Case: Father and Grandson (Degree 2 - paternal)
if w_grandfather == p_id and get_father(p_id) == w_father: return True # W is grandfather of P
if p_grandfather == w_id and get_father(w_id) == p_father: return True # P is grandfather of W
# Case: Paternal Brothers (Degree 1)
w_p_father = get_father(w_id)
p_p_father = get_father(p_id)
if w_p_father and p_p_father and w_p_father == p_p_father: return True # Same paternal father
# Case: Sons of Paternal Brothers (Degree 2)
w_bro_father = get_father(w_id)
p_bro_father = get_father(p_id)
if w_bro_father and p_bro_father and get_father(w_bro_father) == get_father(p_bro_father): return True # Both are sons of brothers (their fathers are brothers)
# Case: Uncle and Nephew (Degree 2)
# This is implicitly covered by sons of brothers, but good to be explicit
# If W is father of P's father, or P is father of W's father
if w_father and get_father(w_father) == p_id: return True # W is son of P's son (W is P's grandson, but paternal)
if p_father and get_father(p_father) == w_id: return True # P is son of W's son (P is W's grandson, but paternal)
return False # No direct paternal disqualification by Scriptural Law
def check_rabbinic_disqualification_A(w_id, p_id):
# This function checks maternal and marital relationships, and degrees.
# It requires extensive traversal and degree calculation.
# Helper to calculate degree of removal (can be complex for indirect paths)
# This needs to handle both ascendance and descendance, and maternal lines.
def calculate_degree_recursive(current_person_id, target_person_id, current_degree, visited_links):
if current_person_id == target_person_id:
return current_degree
# Avoid infinite loops and redundant checks
link_key = tuple(sorted((current_person_id, target_person_id))) + (current_degree,)
if link_key in visited_links:
return float('inf')
visited_links.add(link_key)
# Explore connections:
# 1. Parents
if get_father(current_person_id):
res = calculate_degree_recursive(get_father(current_person_id), target_person_id, current_degree + 1, visited_links.copy())
if res != float('inf'): return res
if get_mother(current_person_id):
res = calculate_degree_recursive(get_mother(current_person_id), target_person_id, current_degree + 1, visited_links.copy())
if res != float('inf'): return res
# 2. Children
for child_id in get_children(current_person_id):
res = calculate_degree_recursive(child_id, target_person_id, current_degree + 1, visited_links.copy())
if res != float('inf'): return res
# 3. Siblings (treat as 1 degree from parent)
for sibling_id in get_siblings(current_person_id):
# This is tricky - siblings are not a direct 'step' in degree calculation from parent to child.
# Degree is usually measured from ancestor to descendant.
# The text says brothers are 1 degree removed. This implies a sibling pair is degree 1 apart.
# Let's simplify: If W and P are siblings, degree is 1.
if (get_father(w_id) and get_father(p_id) and get_father(w_id) == get_father(p_id)) or \
(get_mother(w_id) and get_mother(p_id) and get_mother(w_id) == get_mother(p_id)):
if w_id == sibling_id: # This is not right, this loop iterates through current_person's siblings
pass # Need a better way to check if W and P are siblings
# 4. Spouse relationships (this is complex and needs specific rules)
if get_spouse(current_person_id):
# If current_person is married to X, then X is degree 1 from current_person.
# We need to check disqualifications arising FROM the spouse.
pass # This requires specific marital rules, not just generic traversal
return float('inf')
# --- Simplified Degree Calculation based on text ---
# This is where the complexity lies. The text gives specific degree rules.
# Let's define a function that directly applies these rules.
def get_relationship_degree_and_type(person1_id, person2_id):
# Returns (degree, relationship_type_enum) or (inf, None)
# relationship_type_enum: SCRIPTURAL_PATERNAL, RABBINIC_MATERNAL, RABBINIC_MARITAL
# Check scriptural paternal first
# ... (logic from check_scriptural_disqualification_A, but returning degree)
# Example: if father-son, return (1, SCRIPTURAL_PATERNAL)
# if paternal brothers, return (1, SCRIPTURAL_PATERNAL)
# if sons of paternal brothers, return (2, SCRIPTURAL_PATERNAL)
# if paternal grandfather-grandson, return (2, SCRIPTURAL_PATERNAL)
# Check rabbinic maternal
# ... logic for maternal siblings, children of maternal siblings, etc.
# Example: if maternal siblings, return (1, RABBINIC_MATERNAL)
# if children of maternal siblings, return (2, RABBINIC_MATERNAL)
# Check rabbinic marital - this is the most complex
# Example: if W is married to P's daughter, W is degree 1 from P's daughter, P is degree 0 from P's daughter.
# The text says "husband and wife are considered as being removed by one degree" [31]
# This implies that if W is married to X, W and X are degree 1 apart.
# If P is W's relative, and W is married to P's relative... this needs careful mapping.
# Rule: A man and his wife are removed by one degree [31].
# This means if W is married to X, W->X is degree 1.
# If P is X's son, P is degree 1 from X. So P is degree 2 from W via X.
# If P is X's father, P is degree 1 from X. So P is degree 2 from W via X.
# This interpretation seems problematic based on specific examples later.
# Let's re-read: "A father and his son are considered as one degree removed." [12] This is direct.
# "Brothers - whether maternal or paternal - are considered as one degree removed." [6]
# "Their sons are considered as two degrees removed." [7] (sons of brothers)
# "Their grandsons are three degrees removed." [8] (grandsons of brothers)
# "Two sisters or a brother and a sister - whether paternally or maternally related - are considered as one degree removed." [16]
# The core issue is how to interpret "degree removed" when crossing generations and marital lines.
# The text seems to define degrees based on direct lineage or siblinghood.
# Then it applies these degrees to other relationships.
# Let's use the explicit degree definitions:
# W vs P
# If W is P's father: Degree 1 (Paternal)
# If W is P's son: Degree 1 (Paternal)
# If W is P's paternal brother: Degree 1 (Paternal)
# If W is P's maternal brother: Degree 1 (Maternal)
# If W is P's paternal uncle (father's brother): Degree 2 (Paternal)
# If W is P's paternal nephew (brother's son): Degree 2 (Paternal)
# If W is P's maternal uncle (mother's brother): Degree 2 (Maternal)
# If W is P's maternal nephew (sister's son): Degree 2 (Maternal)
# If W is P's paternal grandson: Degree 2 (Paternal)
# If W is P's paternal great-grandson: Degree 3 (Paternal)
# Marital relationships are inferred.
# "A man and his wife are considered as being removed by one degree." [31]
# This means W testifying for his wife: W is disqualified. W is degree 1 from Wife.
# W testifying for Wife's son: Wife's son is degree 1 from Wife. So Wife's son is degree 2 from W.
# The text says husband may NOT testify for wife's son [32]. This means degree 2 marital is DISQUALIFIED.
# This contradicts the general degree rules [9,10] where 3 can testify for 1 or 2.
# This indicates marital disqualification might be STRICTER or have different rules.
# Let's try to map the disqualification conditions directly from the text.
# Helper to check direct relationship types.
def is_direct_relation(person1, person2, relation_type): # e.g., "father", "son", "brother", "sister"
if relation_type == "father": return get_father(person2) == person1
if relation_type == "son": return get_father(person1) == person2
if relation_type == "brother":
p1_father = get_father(person1)
p2_father = get_father(person2)
p1_mother = get_mother(person1)
p2_mother = get_mother(person2)
return (p1_father and p1_father == p2_father) or (p1_mother and p1_mother == p2_mother)
if relation_type == "sister":
p1_father = get_father(person1)
p2_father = get_father(person2)
p1_mother = get_mother(person1)
p2_mother = get_mother(person2)
return (p1_father and p1_father == p2_father) or (p1_mother and p1_mother == p2_mother)
return False
# Helper to check paternalism
def is_paternal(person1, person2): # Is person1 related to person2 *through their father*?
if get_father(person2) == person1: return True # person1 is father of person2
if get_father(person1) == person2: return True # person2 is father of person1
# Check paternal brothers
if get_father(person1) and get_father(person2) and get_father(person1) == get_father(person2):
return True
return False
# Helper to check maternalism
def is_maternal(person1, person2):
if get_mother(person2) == person1: return True
if get_mother(person1) == person2: return True
# Check maternal siblings
if get_mother(person1) and get_mother(person2) and get_mother(person1) == get_mother(person2):
return True
return False
# --- Applying the rules ---
# 1. Scriptural Paternal Disqualifications [3]
if is_paternal(w_id, p_id):
if is_direct_relation(w_id, p_id, "father") or is_direct_relation(p_id, w_id, "father"): return (1, "SCRIPTURAL_PATERNAL") # Father/Son
# Check paternal brothers
if is_direct_relation(w_id, p_id, "brother") and get_father(w_id) and get_father(w_id) == get_father(p_id): return (1, "SCRIPTURAL_PATERNAL")
# Check sons of paternal brothers (cousins, if fathers are brothers)
w_father = get_father(w_id)
p_father = get_father(p_id)
if w_father and p_father and get_father(w_father) == get_father(p_father):
return (2, "SCRIPTURAL_PATERNAL")
# Check paternal grandfather/grandson
w_grandfather = get_father(get_father(w_id)) if get_father(w_id) else None
p_grandfather = get_father(get_father(p_id)) if get_father(p_id) else None
if w_grandfather and w_grandfather == p_id: return (2, "SCRIPTURAL_PATERNAL")
if p_grandfather and p_grandfather == w_id: return (2, "SCRIPTURAL_PATERNAL")
# 2. Rabbinic Maternal Disqualifications
if is_maternal(w_id, p_id):
if is_direct_relation(w_id, p_id, "brother") and get_mother(w_id) and get_mother(w_id) == get_mother(p_id): return (1, "RABBINIC_MATERNAL")
# Check children of maternal siblings (degree 2)
w_mother = get_mother(w_id)
p_mother = get_mother(p_id)
if w_mother and p_mother and get_mother(w_mother) == get_mother(p_mother):
return (2, "RABBINIC_MATERNAL")
# Check maternal grandfather/grandson (degree 2) - though text implies this is same as paternal for degree calc
w_grandmother = get_mother(get_mother(w_id)) if get_mother(w_id) else None
p_grandmother = get_mother(get_mother(p_id)) if get_mother(p_id) else None
if w_grandmother and w_grandmother == p_id: return (2, "RABBINIC_MATERNAL")
if p_grandmother and p_grandmother == w_id: return (2, "RABBINIC_MATERNAL")
# 3. Rabbinic Marital Disqualifications [19, 20, 23, 24, 31, 32]
# This is where it gets tricky. The text defines "husband and wife removed by one degree" [31]
# and then lists specific cases of disqualification.
# The key is that *if* a disqualification exists via spouse, it propagates.
w_spouse = get_spouse(w_id)
p_spouse = get_spouse(p_id)
# Rule: If W is disqualified for P's spouse, W is disqualified for P.
# Rule: If W is disqualified for someone married to W's relative, W is disqualified for that someone.
# Let's map specific marital relationships and their degrees of removal *from the perspective of the witness*.
# W -> P
# If P is W's wife: Degree 1 (Marital) [31] -> Disqualified [32]
if p_spouse == w_id: return (1, "RABBINIC_MARITAL") # P is W's wife
# If W is P's wife: Degree 1 (Marital) [31] -> W cannot testify for P (as P is her husband)
if w_spouse == p_id: return (1, "RABBINIC_MARITAL") # W is P's wife
# If P is W's wife's son: Degree 2 (via wife) [32] -> Disqualified
if p_spouse and get_father(p_id) == p_spouse and get_spouse(p_spouse) and get_spouse(p_spouse) == w_id:
return (2, "RABBINIC_MARITAL") # P is son of W's wife
if w_spouse and get_father(w_id) == w_spouse and get_spouse(w_spouse) and get_spouse(w_spouse) == p_id:
return (2, "RABBINIC_MARITAL") # W is son of P's wife
# If P is W's wife's daughter: Degree 2 (via wife) [32] -> Disqualified
if p_spouse and get_mother(p_id) == p_spouse and get_spouse(p_spouse) and get_spouse(p_spouse) == w_id:
return (2, "RABBINIC_MARITAL") # P is daughter of W's wife
if w_spouse and get_mother(w_id) == w_spouse and get_spouse(w_spouse) and get_spouse(w_spouse) == p_id:
return (2, "RABBINIC_MARITAL") # W is daughter of P's wife
# If P is W's wife's father: Degree 2 (via wife) [32] -> Disqualified
if p_spouse and get_father(p_spouse) == p_id and get_spouse(p_spouse) and get_spouse(p_spouse) == w_id:
return (2, "RABBINIC_MARITAL") # P is father of W's wife
if w_spouse and get_father(w_spouse) == p_id and get_spouse(p_spouse) and get_spouse(p_spouse) == w_id:
return (2, "RABBINIC_MARITAL") # W is father of P's wife
# If P is W's wife's mother: Degree 2 (via wife) [32] -> Disqualified
if p_spouse and get_mother(p_spouse) == p_id and get_spouse(p_spouse) and get_spouse(p_spouse) == w_id:
return (2, "RABBINIC_MARITAL") # P is mother of W's wife
if w_spouse and get_mother(w_spouse) == p_id and get_spouse(p_spouse) and get_spouse(p_spouse) == w_id:
return (2, "RABBINIC_MARITAL") # W is mother of P's wife
# Rule: Husbands of two sisters are disqualified regarding each other (Degree 1 marital) [23]
# This means if W's wife is sister to P's wife.
w_wife_id = get_spouse(w_id)
p_wife_id = get_spouse(p_id)
if w_wife_id and p_wife_id and is_direct_relation(w_wife_id, p_wife_id, "sister"):
return (1, "RABBINIC_MARITAL")
# Rule: If women are removed by second degrees, their husbands may testify for each other. [21]
# This means if W's wife is 2 degrees from P's wife, W and P are OK.
# Rule: "Whenever a witness is disqualified from testifying on behalf of a colleague because he is married to the witness' relative..." [26]
# This implies a chain: W -> Relative_of_W -> Spouse_of_Relative -> Colleague (P)
# Example: W's brother's wife is P.
# W's brother is Degree 1 (paternal/maternal). His wife is Degree 2 (via marital).
# The text says W *can* testify for P in this case (son/brother of colleague).
# This means the disqualification doesn't cascade through the *colleague's* side of the marital link.
# The critical part is the interpretation of "degree removed" and how it applies to marital links.
# Algorithm A struggles here because it's trying to fit discrete generation steps into a flexible marital structure.
return (float('inf'), None) # No disqualifying relationship found
degree, rel_type = get_relationship_degree_and_type(w_id, p_id)
if degree == float('inf'):
return False # No disqualifying relationship found
# Apply disqualification rules based on degree and type
if rel_type == "SCRIPTURAL_PATERNAL":
if degree <= 2: # Fathers/sons, brothers, sons of brothers, grandfathers/grandsons (paternal)
return True
elif rel_type == "RABBINIC_MATERNAL":
if degree <= 2: # Maternal brothers, children of maternal siblings
return True
elif rel_type == "RABBINIC_MARITAL":
# Marital rules are more nuanced and sometimes stricter than generic degree rules.
# From text [11]: "two who are both two degrees removed... are both disqualified".
# And [11] "one who is two degrees removed and one who is one degree removed are both disqualified".
# This implies degree 1 and 2 are generally disqualified.
# However, specific examples in marital section override or clarify.
# Let's list specific disqualifications from text:
# [32] Husband cannot testify for: wife's son (deg 2), wife's daughter (deg 2), wife's father (deg 2), wife's mother (deg 2).
# This suggests degree 2 marital *is* disqualified.
# [23] Husbands of two sisters are disqualified (deg 1 marital).
# [22] If W married X, and X married Y's daughter, W cannot testify for Y. (W is degree 1 from X, X is degree 1 from Y's daughter, Y is degree 0. So Y's daughter is degree 1 from Y. W is degree 2 from Y's daughter's father Y.)
# This suggests W cannot testify for someone who is his wife's *niece* (daughter of wife's sister). This is Degree 2 or 3 depending on how you count.
# Let's use the explicit disqualifications:
if degree == 1: # e.g., husband/wife, husbands of sisters
return True
if degree == 2: # e.g., wife's son/daughter/parents, wife's sister's husband, wife's sister's son (from another wife?)
# General rule from [11] applies: "two who are both two degrees removed... are both disqualified".
# And [11] "one who is two degrees removed and one who is one degree removed are both disqualified".
# BUT, specific exceptions exist.
# Example [25]: Can testify for son of wife's sister's husband (from another wife). This is a complex 3-party relation.
# This is where Algorithm A struggles without a robust graph.
# For now, assume degree 2 marital is generally disqualified unless explicitly permitted.
# The text is tricky: "Whenever a witness is disqualified from testifying on behalf of a colleague because he is married to the witness' relative, the witness may testify on behalf of the other relatives of that colleague, e.g., his son and his brother." [26]
# This means if W is married to X, and X is P's relative, W is disqualified for P. (This is standard marital disqualification).
# BUT, W *can* testify for P's *son* or *brother*. This is an EXCEPTION.
# This exception is critical and hard to model with simple degree counts.
# Let's assume the general rule from [11] for degree 2 holds, unless a specific exception is hit.
# The exceptions often relate to *who* the marital partner is related to, not just the degree.
return True # For now, assume degree 2 marital is disqualified
# If we reach here, no disqualification found.
return False
# --- The challenge for Algorithm A ---
# The core difficulty is accurately calculating the "degree removed" and "type of relation" for all possible marital scenarios.
# The text implies that degrees are calculated for direct lineage/siblinghood, and then these degrees are applied to marital links,
# but with specific, sometimes contradictory, rules.
# The exceptions in [26] and [25] are particularly hard to encode purely based on degree.
# This approach is very verbose and prone to missing edge cases due to the difficulty of exhaustively enumerating all relationship paths and applying the correct rules.
Pros of Algorithm A:
- Closely follows the textual order of the Mishneh Torah.
- Focuses on explicit generational counting, which is intuitive for simple familial ties.
- Easier to map specific verses to specific code blocks.
Cons of Algorithm A:
- Complexity Explosion: Calculating degrees, especially through marital links, becomes incredibly intricate and computationally expensive. It requires extensive graph traversal or complex recursive functions.
- Brittleness: Small changes in relationship structure can require significant code refactoring.
- Difficulty with Indirect Relationships: Rules like [26] and [25] that involve chains of relationships and exceptions are very hard to encode directly. It requires a deep understanding of how the "degree" concept interacts with marital connections.
- Redundancy: Similar checks might be repeated for different relationship types.
Algorithm B: The Relationship Graph with Attribute Propagation (A Modern, Acharonim-inspired Approach)
This approach models the entire set of people and their relationships as a graph. Each relationship edge has attributes (type, degree, origin of disqualification). Disqualifications then propagate through the graph based on defined rules. This is more like building a knowledge graph and running inference rules.
Core Data Structure:
- Graph: Nodes represent
Personobjects. Edges represent relationships. - Person Object:
id,name,gender,is_convert. - Edge Object:
from_person_id,to_person_id,relationship_type(e.g., "PARENT", "CHILD", "SIBLING", "SPOUSE"),origin_type(e.g., "SCRIPTURAL_PATERNAL", "RABBINIC_MATERNAL", "RABBINIC_MARITAL"),degree_from_source(e.g., 1 for parent/child, 1 for sibling, 2 for grandchild, 2 for nephew/niece),is_disqualified_witness(boolean attribute that can be propagated).
Algorithm Logic (Conceptual Pseudocode):
# Assume a graph database or in-memory graph representation
# Graph has nodes (Persons) and edges (Relationships)
class Person:
def __init__(self, id, name, gender):
self.id = id
self.name = name
self.gender = gender
self.is_convert = False # Default
self.disqualification_flags = set() # Stores reasons for disqualification, e.g., ("SCRIPTURAL_PATERNAL", 2)
class Relationship:
def __init__(self, from_person, to_person, rel_type, origin_type, degree):
self.from_person = from_person
self.to_person = to_person
self.rel_type = rel_type # e.g., PARENT_OF, CHILD_OF, SPOUSE_OF, BROTHER_OF
self.origin_type = origin_type # SCRIPTURAL_PATERNAL, RABBINIC_MATERNAL, RABBINIC_MARITAL
self.degree = degree # Degree of removal from the *source* of disqualification
# --- Initialization and Graph Building ---
# Populate graph with all individuals and their direct relationships.
# For each direct relationship, determine its origin_type and initial degree.
def build_relationship_graph(individuals, direct_relations):
graph = Graph()
for person_data in individuals:
graph.add_node(Person(person_data['id'], person_data['name'], person_data['gender']))
for rel_data in direct_relations:
p1 = graph.get_node(rel_data['from_id'])
p2 = graph.get_node(rel_data['to_id'])
rel_type = rel_data['type']
origin_type, degree = determine_initial_origin_and_degree(p1, p2, rel_type)
if origin_type:
graph.add_edge(Relationship(p1, p2, rel_type, origin_type, degree))
# Add reciprocal edge if relationship is symmetrical in nature
if rel_type in ["BROTHER_OF", "SPOUSE_OF", "PARENT_OF", "CHILD_OF"]: # etc.
rev_origin_type, rev_degree = determine_initial_origin_and_degree(p2, p1, reverse_rel_type(rel_type))
if rev_origin_type:
graph.add_edge(Relationship(p2, p1, reverse_rel_type(rel_type), rev_origin_type, rev_degree))
# After initial graph, propagate disqualifications
propagate_disqualifications(graph)
return graph
def determine_initial_origin_and_degree(person1, person2, rel_type):
# This function maps direct relationships to their disqualification type and degree.
# Examples:
if rel_type == "PARENT_OF": # Person1 is parent of Person2
if get_father(person2) == person1 and is_paternal_lineage(person1, person2):
return "SCRIPTURAL_PATERNAL", 1
if get_mother(person2) == person1 and is_maternal_lineage(person1, person2):
return "RABBINIC_MATERNAL", 1
if rel_type == "BROTHER_OF": # Person1 is brother of Person2
if get_father(person1) and get_father(person1) == get_father(person2):
return "SCRIPTURAL_PATERNAL", 1
if get_mother(person1) and get_mother(person1) == get_mother(person2):
return "RABBINIC_MATERNAL", 1
if rel_type == "SPOUSE_OF": # Person1 is spouse of Person2
return "RABBINIC_MARITAL", 1 # Direct marital link is degree 1
# ... more direct relationships
return None, None # No disqualification for this direct link
# --- Disqualification Propagation Engine ---
def propagate_disqualifications(graph):
# Iteratively apply rules until no new disqualifications are added.
changed = True
while changed:
changed = False
for edge in graph.edges:
w = edge.from_person
p = edge.to_person
original_flags = set(w.disqualification_flags)
# Rule: If W is disqualified for P, then W is disqualified for P's spouse. [19, 20]
if edge.origin_type in ["SCRIPTURAL_PATERNAL", "RABBINIC_MATERNAL", "RABBINIC_MARITAL"]:
# Check if P has a spouse, and if that spouse is not W
for p_spouse_edge in graph.get_edges_for_person(p, "SPOUSE_OF"):
p_spouse = p_spouse_edge.to_person
if p_spouse != w:
# Add disqualification to W for testifying for P_spouse.
# The disqualification type/degree might need adaptation.
# Let's represent it as a link to the original disqualification.
new_flag = (f"MARITAL_PROPAGATION_VIA_{p.id}", edge.origin_type, edge.degree)
if new_flag not in w.disqualification_flags:
w.disqualification_flags.add(new_flag)
changed = True
# Rule: If W is disqualified for someone married to W's relative,
# W may testify for other relatives of that colleague P. [26, 27]
# This means disqualification does NOT propagate from P's *other* relatives to W.
# This is an exclusion rule, handled during the final check.
# Rule: Father/Son, Siblings are Degree 1, their children Degree 2, etc. [6, 7, 8, 16, 17]
# This is mostly handled by initial degree setting, but can propagate.
# E.g., If W is father of P, and P is father of Q, then W is P's father (deg 1), W is Q's grandfather (deg 2).
# This means initial degree calculation needs to be robust.
# Rule: Two people both 2 degrees removed are disqualified. [11]
# Rule: One 2 degrees removed and one 1 degree removed are disqualified. [11]
# This requires checking pairs of relationships.
# This is better handled by a query function that checks *all* relationships between W and P.
# --- Marital Specific Rules ---
# Rule: Husband of wife's sister is disqualified for her husband. [23]
# W is husband of X. P is husband of Y. X and Y are sisters.
# This means W and P are disqualified for each other.
# This needs to be checked when W and P are connected via spouses of sisters.
# Rule: Cannot testify for son/daughter/father/mother of wife. [32]
# This is a specific degree 2 marital disqualification.
# Rule: Consecration = Marriage for disqualification. [33]
# This means setting a temporary 'spouse' relationship.
# --- Refinement ---
# Instead of propagation, let's focus on the eligibility check function using the graph.
# The graph stores relationships with their origin and degree.
# The propagation engine is complex. Let's focus on the query function.
pass # Placeholder for propagation logic
def is_witness_eligible_algorithm_B(witness_id, person_id, graph):
w = graph.get_node(witness_id)
p = graph.get_node(person_id)
if w.is_convert or p.is_convert:
return True # Converts are not considered relatives [5]
# Check direct relationships first
for edge in graph.get_edges_between(w, p):
# Check direct disqualifications
if edge.origin_type == "SCRIPTURAL_PATERNAL" and edge.degree <= 2: return False
if edge.origin_type == "RABBINIC_MATERNAL" and edge.degree <= 2: return False
if edge.origin_type == "RABBINIC_MARITAL" and edge.degree <= 2:
# Marital disqualification has specific nuances.
# The text implies degree 1 and 2 are generally disqualified.
# Let's list the explicit ones from the text and add general rules.
# General rule: If W and P are related by marriage, and the degree of removal via marriage is 1 or 2, it's often disqualified.
# Specific disqualifications: [32]
# Check for exclusion rule [26]: W married to P's relative, but can testify for P's son/brother.
# This means if the disqualifying link is 'W is married to P's relative', then check P's specific relation to W.
# If P is a 'son' or 'brother' of W's relative, eligibility might be restored. This is complex.
# For now, assume degree 1 and 2 marital disqualifies unless specific exception applies.
# We need to model the exceptions carefully.
return False # Tentative: Assume degree 1/2 marital disqualifies.
# --- Indirect Relationship Checks ---
# The text implies disqualification can propagate.
# Example: W -> Wife -> Wife's Son -> P. This is not direct.
# The core rule: "Whenever a person is disqualified from testifying on behalf of a woman, he is also disqualified from testifying on behalf of her husband, for a husband is considered like his wife." [19]
# This means if W cannot testify for X, W cannot testify for X's husband.
# And vice-versa: "whenever a person is disqualified from testifying on behalf of a man, he is also disqualified from testifying on behalf of his wife, for a wife is considered like her husband." [20]
# This is a critical propagation rule for marital links.
# We need to check disqualification for P's spouse, and for W's spouse's relatives.
# Check P's spouse
for p_spouse_edge in graph.get_edges_for_person(p, "SPOUSE_OF"):
p_spouse = p_spouse_edge.to_person
if p_spouse != w:
# If W is disqualified for P's spouse, then W is disqualified for P.
if not is_witness_eligible_algorithm_B(w.id, p_spouse.id, graph):
# This check is recursive and can be problematic.
# A better way: check if W has a disqualifying link to P_spouse.
if check_disqualification_path(w, p_spouse, graph):
# This implies W is disqualified for P.
return False
# Check W's spouse's relatives
for w_spouse_edge in graph.get_edges_for_person(w, "SPOUSE_OF"):
w_spouse = w_spouse_edge.to_person
# If W is disqualified for his spouse, he is disqualified for testifying for P IF P is related to W's spouse.
# This is essentially checking if P is a relative of W's spouse.
if check_disqualification_path(w, p, graph, via_spouse_of=w_spouse):
return False
# Specific checks for complex marital scenarios:
# Husband of wife's sister [23]
# W's wife = X, P's wife = Y. X and Y are sisters. W and P disqualified for each other.
w_wife_rel = graph.get_relationship(w, w.spouse, "SPOUSE_OF")
p_wife_rel = graph.get_relationship(p, p.spouse, "SPOUSE_OF")
if w_wife_rel and p_wife_rel:
x = w_wife_rel.to_person
y = p_wife_rel.to_person
for edge_x_y in graph.get_edges_between(x, y):
if edge_x_y.rel_type == "SISTER_OF" and edge_x_y.origin_type.startswith("RABBINIC"):
return False # Disqualified
# Rule [26]: W married to P's relative (say X). W disqualified for P. BUT W can testify for P's son/brother.
# This needs to be checked during the final eligibility determination.
# If a disqualification is found via marital link (e.g., W is married to P's sister),
# we then check if P is specifically P's son or brother.
# --- Final Check for Eligibility ---
# Iterate through all relationships and disqualification paths.
# If any path leads to disqualification, return False.
# Apply specific exceptions.
# Example: Check for disqualification paths.
if check_disqualification_path(w, p, graph):
return False
# If converts, they are eligible.
if w.is_convert or p.is_convert:
return True # Covered earlier, but good to re-emphasize.
# If no disqualification found after all checks.
return True
def check_disqualification_path(person1, person2, graph, via_spouse_of=None):
# This function checks if there's a disqualifying path between person1 and person2.
# It needs to implement the degree rules and propagation rules.
# --- Direct Relationship Check ---
for edge in graph.get_edges_between(person1, person2):
if edge.origin_type == "SCRIPTURAL_PATERNAL" and edge.degree <= 2: return True
if edge.origin_type == "RABBINIC_MATERNAL" and edge.degree <= 2: return True
if edge.origin_type == "RABBINIC_MARITAL":
# Degree 1 and 2 marital generally disqualify.
# We need to check specific exceptions here.
if edge.degree <= 2:
# Check for exception [26]: W married to P's relative X. W disqualified for P.
# But W can testify for P's son or brother.
# If the current edge represents W married to X, and X is related to P,
# we need to check if P is a son or brother of X (or P's other relatives).
# This is complex: it requires knowing P's relationship *to the original person* that the marital link is tied to.
# Let's simplify: if direct marital link of degree 1 or 2, assume disqualified unless rule 26 exception applies.
# Rule 26: "Whenever a witness is disqualified from testifying on behalf of a colleague because he is married to the witness' relative, the witness may testify on behalf of the other relatives of that colleague, e.g., his son and his brother."
# This means the disqualification *propagates* from W's relative to their spouse, and then potentially to the spouse's colleague.
# But if the colleague is a *closer* relative of the original person (e.g., son/brother), eligibility is restored.
# This rule is about *restoring* eligibility, not *creating* disqualification.
# So, if a disqualification is found, we then check for this restoration.
return True # Found direct marital disqualification.
# --- Indirect Relationship Checks (Propagation) ---
# Rule: Disqualification for spouse propagates to the other spouse. [19, 20]
# If person1 is disqualified for X, and X is married to person2, then person1 is disqualified for person2.
# This requires checking if person2 is the spouse of someone person1 is disqualified for.
for related_person_edge in graph.get_edges_from_person(person1): # All people person1 is related to
# Check if person1 is disqualified for related_person
if is_disqualified_direct(person1, related_person_edge.to_person, graph): # Helper to check direct disqualification
# If related_person is married to person2
for spouse_edge in graph.get_edges_for_person(related_person_edge.to_person, "SPOUSE_OF"):
if spouse_edge.to_person == person2:
return True # Disqualification propagated through spouse
# Rule: "Whenever two women are removed by second degrees, their husbands may testify on behalf of each other." [21]
# This is an *exception* to marital disqualification. Needs to be checked.
# If W and P are husbands, and their wives are 2 degrees apart (e.g., sisters).
# This means W and P are NOT disqualified.
# Rule [25]: Testify for son of husband of wife's sister (born to another wife).
# This requires traversing multiple marital and familial links.
return False
def is_disqualified_direct(person1, person2, graph):
# Helper function to check *direct* disqualification based on established edge attributes.
for edge in graph.get_edges_between(person1, person2):
if edge.origin_type == "SCRIPTURAL_PATERNAL" and edge.degree <= 2: return True
if edge.origin_type == "RABBINIC_MATERNAL" and edge.degree <= 2: return True
if edge.origin_type == "RABBINIC_MARITAL" and edge.degree <= 2:
# Need to apply exceptions here.
return True
return False
# --- Final Eligibility Check ---
def is_eligible(witness_id, person_id, graph):
w = graph.get_node(witness_id)
p = graph.get_node(person_id)
if w.is_convert or p.is_convert: return True # Converts are not relatives.
# Check all possible disqualifying paths and relationships.
# This is where the complexity of Acharonim lies - building a comprehensive check.
# 1. Direct Relationship Checks:
for edge in graph.get_edges_between(w, p):
if edge.origin_type == "SCRIPTURAL_PATERNAL" and edge.degree <= 2: return False
if edge.origin_type == "RABBINIC_MATERNAL" and edge.degree <= 2: return False
if edge.origin_type == "RABBINIC_MARITAL":
# Apply degree rules and specific exceptions for marital.
if edge.degree <= 2:
# Check for exception [26] - this requires knowing P's *specific* relation to the original person.
# This is very difficult to generalize. Let's assume general disqualification for deg 1/2 marital for now.
return False
# 2. Indirect Relationship Checks (Propagation):
# Rule [19, 20]: Disqualification for spouse propagates.
# If W is disqualified for P's spouse, W is disqualified for P.
# If P is disqualified for W's spouse, P is disqualified for W. (Symmetric)
# This means we need to check if P is disqualified for W's spouse, or W is disqualified for P's spouse.
# Check if P is disqualified for W's spouse
for w_spouse_edge in graph.get_edges_for_person(w, "SPOUSE_OF"):
w_spouse = w_spouse_edge.to_person
if is_disqualified_via_path(p, w_spouse, graph): # Check if P is disqualified for W's spouse
return False
# Check if W is disqualified for P's spouse
for p_spouse_edge in graph.get_edges_for_person(p, "SPOUSE_OF"):
p_spouse = p_spouse_edge.to_person
if is_disqualified_via_path(w, p_spouse, graph): # Check if W is disqualified for P's spouse
return False
# 3. Specific Complex Marital Rules:
# Rule [23]: Husbands of sisters disqualified for each other.
w_wife_id = graph.get_spouse_id(w.id)
p_wife_id = graph.get_spouse_id(p.id)
if w_wife_id and p_wife_id:
if graph.are_sisters(w_wife_id, p_wife_id):
return False # Disqualified
# Rule [21]: Husbands of women 2 degrees apart can testify. (Exception to general rule)
# This means if wives are sisters (1 degree apart), husbands are disqualified (as per above).
# If wives are cousins (2 degrees apart), husbands can testify.
# This needs a check: are the wives related, and what degree?
# Rule [25]: Son of husband of wife's sister (born to another wife).
# This requires a very specific path check.
# 4. Apply Exception [26] / [27]
# If a disqualification was found (e.g., direct marital link), check if P is a son or brother of W's relative.
# This is a conditional override. If a disqualification is detected, we *then* check this.
# This is hard to implement generally without a specific structure.
# If no disqualification found through any path or rule.
return True
def is_disqualified_via_path(person1, person2, graph):
# This is the core recursive/iterative function to check disqualification.
# It needs to handle direct links, indirect links, and propagation rules.
# It must also handle the exceptions.
# Base case: Direct relationship check
for edge in graph.get_edges_between(person1, person2):
if edge.origin_type == "SCRIPTURAL_PATERNAL" and edge.degree <= 2:
# Check for exception [26] - if person2 is son/brother of person1's relative's spouse.
return True # Disqualified
if edge.origin_type == "RABBINIC_MATERNAL" and edge.degree <= 2:
return True # Disqualified
if edge.origin_type == "RABBINIC_MARITAL":
if edge.degree <= 2:
# Apply specific marital rules and exceptions here.
# E.g., rule [26] exception: if person2 is son/brother of person1's relative's spouse
return True # Disqualified (for now, assuming general rule applies)
# Recursive step: Check indirect relationships and propagation
# Rule [19, 20]: Disqualification propagates via spouses.
# If person1 is disqualified for X, and X is married to person2, then person1 is disqualified for person2.
for related_person_edge in graph.get_edges_from_person(person1): # All people person1 is related to
related_person = related_person_edge.to_person
if is_disqualified_via_path(person1, related_person, graph): # If person1 disqualified for related_person
for spouse_edge in graph.get_edges_for_person(related_person, "SPOUSE_OF"):
if spouse_edge.to_person == person2:
return True # Disqualification propagated
# Specific Rule [23] check: husbands of sisters
# ...
return False
Pros of Algorithm B:
- Scalability and Flexibility: Graph structures are excellent for representing complex interdependencies. Adding new rules or relationship types is easier.
- Modularity: Disqualification rules (propagation, exceptions) can be implemented as separate modules or inference rules.
- Clarity of Relationship Attributes: Explicitly storing
origin_typeanddegreeon edges makes the "why" of disqualification transparent. - Handles Propagation Naturally: Graph traversal is designed for finding paths and dependencies.
- More Robust for Complex Cases: Better suited for handling intricate marital relationships and cascading disqualifications.
- Acharonim Spirit: This approach aligns with how later scholars built upon earlier understandings, creating more comprehensive and systematic frameworks.
Cons of Algorithm B:
- Initial Setup Overhead: Building the graph requires significant effort in defining all individuals and their direct relationships with their attributes.
- Algorithmic Complexity: While more systematic, the pathfinding and propagation algorithms can still be computationally intensive, depending on the graph size and rule complexity.
- Abstraction: May require more mental overhead to understand the underlying graph logic compared to the direct textual mapping of Algorithm A.
Algorithm B is clearly the more "nerdy" and powerful approach, allowing us to build a robust witness eligibility engine. It's like moving from a simple script to a full-fledged relational database with complex query logic.
Edge Cases – Inputs That Break Naïve Logic
Here are two scenarios that would likely cause a simple, rule-based system (a "naïve" implementation) to falter, but would be handled by our more sophisticated models. These are the "unit tests" that reveal the system's weaknesses.
Edge Case 1: The Double-Marinated Relative
Scenario: A person, let's call him David, wants to testify for his wife's nephew, Ethan. David's wife, Sarah, is the sister of Mark. Mark is Ethan's father.
Let's break down the relationships from David's perspective:
- David is married to Sarah. (Relationship 1: David <-> Sarah - Marital, Degree 1)
- Sarah is the sister of Mark. (Relationship 2: Sarah <-> Mark - Siblings, Degree 1 Maternal)
- Mark is the father of Ethan. (Relationship 3: Mark <-> Ethan - Parent/Child, Degree 1 Paternal)
Naïve Logic Failure: A naïve system might only look at the direct relationship between David and Ethan. Since there's no direct familial link (father, son, brother, etc.) and no obvious marital link directly between David and Ethan, it might erroneously declare David eligible. Or, it might get confused by the marital link through Sarah and not correctly trace the disqualification.
- If it only checks direct relations: "No direct relation between David and Ethan. Eligible."
- If it sees "David is married to Sarah" and "Sarah is related to Ethan's father," it might not know how to combine these to determine disqualification for Ethan.
Expected Output (According to Mishneh Torah): David is DISQUALIFIED.
Explanation:
- David is married to Sarah (Degree 1 Marital). By rule [31], a man and his wife are removed by one degree.
- Sarah is the sister of Mark (Degree 1 Maternal).
- Mark is the father of Ethan (Degree 1 Paternal).
The crucial rule here is [19]: "Whenever a person is disqualified from testifying on behalf of a woman, he is also disqualified from testifying on behalf of her husband, for a husband is considered like his wife." And its corollary [20]: "Conversely, whenever a person is disqualified from testifying on behalf of a man, he is also disqualified from testifying on behalf of his wife, for a wife is considered like her husband."
Let's trace this:
- David is married to Sarah. This establishes a close marital tie (Degree 1).
- David would generally be disqualified from testifying for his wife's relatives. Who are Sarah's relatives? Mark is her brother.
- The text states [24]: "a person should not testify on behalf of the son of his wife's sister..." This is directly analogous. David's wife is Sarah. Sarah's brother is Mark. Mark's son is Ethan. So, David should not testify for Ethan.
- Even if we didn't have [24] specifically, rule [19/20] applies. If David is disqualified for Sarah, he's disqualified for her husband. This is a bit circular.
- Let's use the structure: "A person should not testify on behalf of the son of his wife's sister." [24]
- David's wife = Sarah.
- Sarah's sister = No direct sister mentioned, but Sarah's brother is Mark.
- The parallel is "son of his wife's brother".
- The text says [32] "Hence a husband may not testify on behalf of his wife's son..."
- If David is disqualified for Sarah (his wife), he is disqualified for her direct relatives.
- The disqualification propagates through the marital link. David is married to Sarah. Sarah's brother is Mark. Mark's son is Ethan.
- David is disqualified for Sarah (his wife). Sarah is a direct relative of Mark. Mark is the father of Ethan.
- The disqualification cascades: David is disqualified for Sarah. Sarah is disqualified for Mark. Mark is disqualified for Ethan.
- The critical link is Rule [20]: "whenever a person is disqualified from testifying on behalf of a man, he is also disqualified from testifying on behalf of his wife..."
- Applying this backwards: If David is disqualified for Ethan, he's disqualified for Ethan's father (Mark). If David is disqualified for Mark, he's disqualified for Mark's sibling (Sarah). If David is disqualified for Sarah, he's disqualified for Sarah's husband (David himself), which is redundant, but it shows the propagation.
- The most direct application is Rule [24], which is highly analogous: "a person should not testify on behalf of the son of his wife's sister". Here, it's the son of his wife's brother. The principle of disqualification through the wife's lineage is strong.
The key is that the marital relationship creates a "proxy" status. David is disqualified for Sarah. Because Sarah is Mark's sister, this disqualification could extend to Mark. And because Mark is Ethan's father, it extends to Ethan.
Algorithm B handles this by tracing the path:
- David -> Spouse (Sarah) [Marital, Deg 1]
- Sarah -> Brother (Mark) [Maternal Sibling, Deg 1]
- Mark -> Son (Ethan) [Paternal Parent/Child, Deg 1]
The disqualification from Mark to Ethan (Scriptural Paternal, Deg 1) is clear. The disqualification from Sarah to Mark (Maternal Sibling, Deg 1) is clear. The disqualification from David to Sarah (Marital, Deg 1) is clear.
The rule [19/20] is the propagation engine. If W cannot testify for P, W cannot testify for P's spouse.
- David cannot testify for Mark (because Mark is Sarah's brother, and David is disqualified for Sarah).
- Since David cannot testify for Mark, and Mark is Ethan's father, this disqualification might extend.
- The text [32] explicitly states husband cannot testify for wife's son. This is the strongest indicator. David's wife is Sarah. Ethan is the son of Sarah's brother Mark. This is equivalent to "wife's nephew" in terms of closeness.
Our Algorithm B would model this by:
- Recognizing David-Sarah as SPOUSE_OF (Marital, Deg 1).
- Recognizing Sarah-Mark as SIBLING_OF (Maternal, Deg 1).
- Recognizing Mark-Ethan as PARENT_OF (Paternal, Deg 1).
When checking David for Ethan:
- It would first look for direct disqualification. None.
- Then, it checks indirect disqualification via propagation.
- It sees David is married to Sarah. It checks if David is disqualified for Sarah's relatives.
- It finds Sarah is Mark's sister, and Mark is Ethan's father.
- The rule [32] "husband may not testify on behalf of his wife's son" is the closest direct parallel. Ethan is the son of David's wife's brother. This is typically considered a degree 2 or 3 marital disqualification.
Edge Case 2: The Convert's Twin and His Father-in-Law
Scenario: Avi is a convert. His twin brother, Benny (who is also a convert), wants to testify for Chani. Chani is Avi's wife. Benny wants to testify for Avi's father-in-law, David.
Let's break down the relationships:
- Avi and Benny are twin brothers, both converts.
- Avi is married to Chani.
- Chani's father is David.
Naïve Logic Failure: A naïve system might see:
- Benny wants to testify for David.
- Is Benny related to David? No direct familial tie.
- Is Benny related to David by marriage? No direct marital tie.
- The system might overlook the "convert" status as a special flag, or it might incorrectly apply rules about relatives to converts.
- It might see "Avi is married to Chani" and "Chani's father is David," and incorrectly assume Benny, as Avi's brother, inherits disqualification.
Expected Output (According to Mishneh Torah): Benny is ELIGIBLE.
Explanation: This case tests two critical rules:
Converts are not relatives: Mishneh Torah, Testimony 13:1:5 states: "Converts are not considered as relatives. Even two twin brothers who convert may testify on each others behalf. For a convert is considered as a newborn child."
- Since both Avi and Benny are converts, their fraternal relationship does not create a disqualifying familial link for testimony purposes. They are treated as strangers to each other in the context of witness disqualification.
Marital disqualification propagation:
- Avi is married to Chani.
- Chani's father is David.
- This means Avi is disqualified from testifying for David (his father-in-law). Rule [32] lists "his wife's father" as someone a husband may not testify for. This is a degree 2 marital disqualification.
Now, consider Benny.
- Benny wants to testify for David.
- Benny is a convert. This means Benny is not considered a relative of Avi.
- Therefore, the fact that Avi (Benny's brother) is disqualified for David does not disqualify Benny. Benny has no disqualifying relationship to David.
Algorithm B handles this by:
- Adding
is_convert=Trueto Avi and Benny. - When checking Benny for David:
- The first check in
is_witness_eligible_algorithm_Bisif w.is_convert or p.is_convert: return True. This immediately handles the core of the problem. Benny (witness) is a convert. David (person) is not. So, Benny is eligible. - Even if that initial check were removed, the subsequent relationship checks would fail to find any disqualifying link between Benny and David. Benny is not related to David by blood, and their marital connections are indirect and mediated by Avi, who is not considered a relative of Benny for this purpose.
- The first check in
This scenario highlights how specific status attributes (like "convert") and precise definitions of relationship types are crucial for correct system operation. The "newborn child" analogy is key: a convert starts with a clean slate, unaffected by familial ties that would disqualify a non-convert.
Refactor – One Minimal Change for Clarity
The current text, while comprehensive, can be a bit like a deeply nested set of if-else statements without clear function definitions. The "degree removed" concept is applied inconsistently across paternal, maternal, and marital links.
The Minimal Change: Explicitly define "Degree of Removal" as a function that takes two people and returns a tuple: (degree, disqualification_type). This function would encapsulate all the complex logic for calculating degrees and types based on Scriptural, Rabbinic, and Marital rules, including exceptions.
Current State (Conceptual): Disqualification logic is spread across multiple paragraphs, with degree calculations interwoven with specific relationship descriptions.
Refactored State (Conceptual):
Imagine a central "Relationship Engine" or "Disqualification Calculator" function:
def calculate_disqualification_status(person1_id, person2_id, graph):
"""
Calculates the disqualification status between two individuals.
Args:
person1_id: ID of the potential witness.
person2_id: ID of the person they might testify for.
graph: The relationship graph.
Returns:
A tuple: (is_disqualified: bool, reason: str, degree: int, type: str)
Returns (False, "No disqualification", 0, "None") if eligible.
"""
w = graph.get_node(person1_id)
p = graph.get_node(person2_id)
# Rule: Converts are not relatives.
if w.is_convert or p.is_convert:
return (False, "Convert status", 0, "None")
# --- Step 1: Check Direct Relationships ---
direct_disqualifications = []
for edge in graph.get_edges_between(w, p):
# Apply Scriptural Paternal rules
if edge.origin_type == "SCRIPTURAL_PATERNAL" and edge.degree <= 2:
direct_disqualifications.append({"disqualified": True, "reason": "Scriptural Paternal", "degree": edge.degree, "type": "SCRIPTURAL_PATERNAL"})
# Apply Rabbinic Maternal rules
if edge.origin_type == "RABBINIC_MATERNAL" and edge.degree <= 2:
direct_disqualifications.append({"disqualified": True, "reason": "Rabbinic Maternal", "degree": edge.degree, "type": "RABBINIC_MATERNAL"})
# Apply Rabbinic Marital rules (with specific checks)
if edge.origin_type == "RABBINIC_MARITAL" and edge.degree <= 2:
# This is where specific marital rules and exceptions are applied.
# E.g., check for [32] cases, [23] husbands of sisters, [21] exception, etc.
# This sub-logic becomes a detailed sub-function.
is_marital_disqualified, marital_reason, marital_degree = apply_marital_rules(w, p, edge, graph)
if is_marital_disqualified:
direct_disqualifications.append({"disqualified": True, "reason": marital_reason, "degree": marital_degree, "type": "RABBINIC_MARITAL"})
if direct_disqualifications:
# For simplicity, return the first disqualification found, or aggregate if needed.
# In a real system, might return the "strongest" disqualification.
dq = direct_disqualifications[0]
return (True, dq["reason"], dq["degree"], dq["type"])
# --- Step 2: Check Indirect Relationships & Propagation ---
# This part involves graph traversal and applying rules like [19, 20], [26], etc.
# This would be another complex function call.
indirect_disqualification_result = check_indirect_disqualification(w, p, graph)
if indirect_disqualification_result[0]: # If disqualified indirectly
return indirect_disqualification_result
# --- Step 3: Final Checks and Exceptions ---
# E.g., rule [26] exception might override a prior disqualification.
return (False, "No disqualification", 0, "None")
# Helper function for marital rules
def apply_marital_rules(person1, person2, edge, graph):
# ... complex logic for marital relationships, including degrees, exceptions [21, 23, 25, 26], etc.
# Returns (is_disqualified, reason, degree)
pass
# Helper function for indirect checks
def check_indirect_disqualification(person1, person2, graph):
# ... logic for propagation via spouses [19, 20], and other indirect paths.
# Returns (is_disqualified, reason, degree, type)
pass
Impact of the Refactor: This refactoring doesn't change the rules, but it reorganizes them. It creates a clear "API" for determining disqualification. Instead of scattered logic, we have a central, well-defined process. This makes the system:
- More Understandable: The flow of logic is explicit.
- More Maintainable: Changes or additions to rules are localized within specific functions.
- More Testable: Each function can be unit-tested independently.
- More Robust: Less chance of subtle errors from interacting
if-elsechains.
It's like moving from unstructured prose to well-documented functions in a codebase. The core "business logic" of disqualification is now modularized and reusable.
Takeaway
Mishneh Torah, Testimony Chapter 13, presents a fascinating case study in how legal and ethical principles are encoded into systems. What appears as simple disqualification of relatives is, under the lens of systems thinking, a complex web of rules, exceptions, and propagation mechanisms.
We've seen how:
- Layered Abstraction: Scriptural Law forms the foundational layer, with Rabbinic decrees acting as enhancements and extensions.
- Dependency Management: Relationships create dependencies. Disqualification for one person can impact the eligibility of another through marital links (like a cascaded delete in a database).
- Attribute Propagation: Disqualification status isn't just a property of a single relationship; it can propagate based on the attributes of those relationships (type, degree).
- Rule Engines: The text functions as a set of inference rules. Algorithm B, the graph-based approach, is essentially building a rule engine to process these relationships.
- Edge Cases as Stress Tests: Scenarios involving converts or complex marital chains reveal the limitations of simpler models and highlight the need for precise rule definitions and attribute handling.
By translating these sugyot into algorithmic models, we gain a deeper appreciation for the meticulous logic of our Sages. They didn't just state rules; they engineered a system of justice with intricate checks and balances, ensuring fairness and integrity in testimony. This journey from ancient text to algorithmic blueprint shows that the spirit of "nerd-joy" and elegant problem-solving is timeless!
derekhlearning.com