From Arithmetic to Algebra - The Discovery of Equality, Equations and Double-Entry Accounting in Khipus
by Ashok Khosla and AgustĂn Da Fieno Delucchi, September 2026
KH0696 - Photo by Mackinley FitzPatrick, Click on image for a larger view
Abstract
This article first surveys existing scholarship on khipu arithmetic. Then, with the addition of new khipu âoperatorsâ, we transform simple khipu addition and subtraction to allow for a more complete algebraic structure that provides equational capabilities.
Previous work by Manuel Medrano and Ashok Khosla generalized the work of Marcia and Robert Ascher to confirm and identify numerous types of addition and subtraction operations. Our previous algebraic structure had a 0 (an unknotted cord), a 1, and the operators â+â and â-â, i.e., it had the full algebraic signature of an additive abelian group. In effect, the group had one operator, addition, with its inverse, subtraction.
What khipu arithmetic did not have was an equal sign and the ability to express equations of equality (a ring). The discovery of an equality operator transforms previous simple arithmetic to the next level of algebraic structure. For example equations like this are now possible:
\(A + B = C + D\) where \(A,\ B,\ C,\ D\ =\ \displaystyle\sum_{p_x}^{p_y}\ or\ Cord\ {p_i}\)
We propose two candidate khipu signs:
An equality marker = , noted by an Equal Sum cord whose value matches both right and left-handed summand ranges. Such a marker can be interpreted as representing an equality relation, i.e. A+B = C+D.
A set of optional parenthetical delimiters, ( and ), noted by Figure-8-Knots, that mark those summand ranges
Combining established addition signs with the new signs, we demonstrate an illustration of these signsâ interogative power by using an Equal Sum equality marker on khipu KH0696 to yield a clear, legible template for Double-Entry Accounting logic, including crosstabs, encoded within its structure. Corpus-wide analyses show that for larger khipus, multiple Equal Sums exist, with the sums forming a network graph of interrelated equations.
0. Introduction - Equal Sums and Double Entry Accounting
All the local caçiques come to these towns along the road to serve [âŠ] [the accountants] have a store of firewood and maize and everything else, and they count by some knots in ropes what each caçique has brought. And when they brought us a few loads of firewood or sheep or maize or chicha, they removed the knots from those who had it in charge, and tied it elsewhere: so that in everything they have a very great account and reason.
Pizarro, Hernando. (1533). âA los señores oydores de la audiencia real de su magestad.â
Double-Entry Accounting, the famous system of accounting created by Italian merchants in the 13th through 15th century, is built on the fundamental equation of:
Assets = Equities + Liabilities
Hernando Pizarroâs account above is a statement of the double-entry accounting equation in practice. How might this be done in a khipu?
To effect this, first we need two arithmetical âoperatorsâ; a + (plus sign), and an = (equal sign). The plus sign has been well documented by Medrano and Khosla in their article on Ascher Summations, and on the Khipu Field Guide. What we need now is an Equal sign.
First, lets step back and look at the history of khipu arithmetic.
1. The Arithmetical Operators, +, -, Ă, Ă·, â, (,), and =
1.1 + Plus: The Discovery of Addition
1.1.1 Locke, Ascher, and Clindaniel
Leland Locke first noted the use of numeric summations in khipu in 1923. Locke observed that a top cordâs value was the sum of the values of the cords that were tied to it. That idea was later expanded by Robert and Marcia Ascher in 1975, who discovered numerous summations in the 200+ khipus they documented in their Databooks. In Jon Clindanielâs Harvard PhD Thesis, on the Incahuasi khipus, he proposed that white cords were involved in subtraction. While this turned out not to be the case (the reading was the mirror inverse - it was addition), it was a novel use of color as a sign being posited for addition.
1.1.2 Ascher Pendant Sum Types
In 2025, Manuel Medrano and Ashok Khosla, extrapolated and generalized the most common summation relationships based on Marcia and Robert Aschersâ observations of khipus in their Databooks. Medrano and Khosla define Ascher Pendant Sums as a pendant cord that is the sum of a range of other pendants. Three common types of Sums exist, and they occur in two directions, Left versus Right. The three common types are Pendant Pendant Sums, Indexed Pendant Sums, and Colored Pendant Sums.
Pendant Pendant Sums have the sum cord equal to the sum of the values of a set of contiguous summand cords, for example:
G1P1 = G3P5 + G4P1 + G4P2 (A subset of contiguous pendant cords from Group 3 and 4)
Indexed Pendant Sums have the sum cord equal to the sum of the values of the indexed (position of the cord in its group) summand cords, for example:
G1P4 = G3P4 + G4P4 + G5P4 (Every 4th pendant from Groups 3,4, and 5)
Colored Pendant Sums have the sum cord equal to the sum of the values of colored summand cords across groups, regardless of their position, for example:
G1PRed = G3PRed + G4PRed + G5PRed (Every Red pendant from Groups 3,4, and 5)
These three types of sums often exist simultaneously. A visual inspection of their network graphs can guide the reveal of these summation type layers and their juxtapositions. Indexed pendant sums and colored pendant sums are often used as sum hierarchies - for example, the Purucucho khipu hierarchy studied by Carrie Brezine in Brezine2005 and the restatement of KH0082/AS069 and KH0083/AS070 by Karen Thompson in Thompson2018.
1.1.3 Ascher Sum Directions
Sums can be in two directions: Right-Handed and Left-Handed. A Right-Handed sum has the summands are to the right of the sum cord (think of your right-handed thumb summing the values of the right hand fingers). The obverse, Left-Handed Sums, have the summands (the left fingers) to the left of the left thumb (the sum).
Make a fist, then turn your hands so the thumbs are sticking in and facing each other.
A Right-Handed Sum has 10 = 1+2+3+4 with the sum on the right-thumb, and the fingers representing 1,2,3,4.
Right-handed sums are conventionally colored as Red (using the mnemonic R for Red/Right-Handed)
A Left-Handed Sum has 1+2+3+4 = 10 with the sum on the left-thumb, and the fingers representing 1,2,3,4.
Left-handed sums are conventionally colored as Blue.
\(\sum_{i,j=A}^{B} G_i P_j = LeftHandedSum\)
As you will come to see, sum directions are important - like links in a spreadsheet, they provide a network graph of summations. That network graph can be analyzed to understand the structure of the khipu. Here for example is the pendant-pendant sum network graph for KH0696. Notice all the arrows, both red and blue, that link into g4p1.
Click on image for a larger view
1.1.4 Sum Signs
Medrano and Khosla observed that the sum cord was most commonly White. In addition, since it often was of a higher value than the often neighboring summand cords, it could be more easily visually identified as a sum. However, markers for summand ranges (which were not visually as obvious) remained undiscovered until the authorsâ discovery of Figure-8-Knots as summand range markers.
1.2 - Minus: The Discovery of Subtraction
The Aschers also noticed that some khipus had pendant-subsidiary differences. For example, KH0031 has a property that relates adjacent pendants to their neighbor and their neighborâs subsidiary.
In group 1, wherever the pendant value is larger than its subsidiaryâs value, the difference is the value of another pendant in the group. That is:
By contrast, in group 8, whenever the pendant value is smaller than its subsidiaryâ s value, the difference is the value of another pendant in the group. Namely,
This pattern, constrained, by nearest neighbor, not just by any other pendant in the group, was described by Medrano & Khosla and is now called a pendant-subsidiary difference relationship. Although subtractions are uncommon in the KFG corpus (~5% of the total of pendant pendant sums, indexed pendant sums, and colored pendant sums), pendant-subsidiary difference relationships occur with enough frequency to be considered a subtraction operator. Nonetheless, the corpus is clearly telling us to be cautious when framing a khipu equation as a subtraction. It may be masquerading, with itâs true nature being an addition, not a subtraction.
1.3 (,) Range: The Discovery of Figure 8 Knots as Parenthetical Summand Range Markers
Many of the sets of summand cords in KH0468 also either begin or end with the value one, designated by a so-called figure eight knot.
This observation was later investigated by the authors. It was discovered that figure-8-knots were used as optional left and/or right parentheses to mark summand regions. Since the focus of this article is on the algebra of Equal Sums, we will not delve deeply into the details of Figure-8-Knots as summand range markers. However, considerable elaboration of Figure-8-Knots as summand markers is provided in the KhipuFieldGuide page dedicated to Figure-8-Knots.
1.4 Ă, Ă·, â Times, Divide & Square Root: The (Still Missing) Discovery of Higher Order Arithmetic
There is little actual evidence of multiplication and division represented in the literature. Numerous instance exist in Ascherâs Databooks, of muliplication and division by 2 and 10 exist, but the authors have not uncovered actual khipu examples of generalized multiplication or division where three cords exist, x, y, and z, and x*y=z or x/y=z, where x,y,and z are all non-trivial values. For example, when we simultaneously search for:
Three contiguous pendant cords
Any two of the cords are factors, and the third is the product
The values are non-trivial
We find only 9 examples in our entire KFG database:
KH0075 p11=7, p12=35, p13=5
KH0081 p46=39, p47=3, p48=117
KH0130 p7=52, p8=2, p9=26
KH0156 p174=28, p175=4, p176=7
KH0303 p25=156, p26=13, p27=12
KH0304 p25=156, p26=13, p27=12 (khipu identical to KH0303)
KH0326 p105=7, p106=119, p107=17
KH0476 p46=36, p47=6, p48=6
KH0600 p107=4, p108=52, p109=13
Urton has proposed that taxation by a fixed amount existed in the Incahuasi khipus KH0503, KH0504, KH0505, and KH0514. There is no multiplication, however in these khipus, just a pre-multiplication step with the result shown in the khipu as a âtaxâ on the state.
Ascher has noted that KH0229(see notes 9-11) has cords that are multiples of 17, and two numbers that as ratios approximate the sqrt of 2.
1.5 = Equals: The Discovery of Equal Sums
Enabled by new Data Visualization techniques, it has been discovered that sum cords can simultaneously participate as a Left-Handed and Right-Handed sum. Named Equal Sums, khipus with equal sums exhibit intriguing characteristics that are described in this study.
The basic idea of an Equal Sum is that given a set of pendant cords, PL1, PL2,PL3, PLn, on the left, and a set of pendant cords, on the right, PR1, PR2,PR3, PRn that the sum of ÎŁPLeft i, and the sum of ÎŁPRight j are = (âequalâ). Note that the number of summands on the left does not have to equal the number of summands on the right, just that their sums are equal.
where the cord ordinals B-A >=2 and D-C >=2 (ie. there must be at least two summands on each side)
This restriction of two summands is artificial (favoring precision over recall in our search for Equal Sums). Consequently, more than one summand must be represented from either side. This means the Equal Sum cord is representing a multiterm equations. i.e.
Given two equations:
1.) \(A + B + C = D + E\) 2.) \({p_1} = A + B + C\)
then, because these are equations, substitution and cancellation are possible. i.e.
\(A + B + C + K = D + E + K\) \(\Rightarrow A + B + C = D + E\)Cancel Ks \(\Rightarrow A + B + C - (D + E) = 0\)Rearrange terms \(\Rightarrow {p_1} = D + E\)Substitution
These types of equal sums exist for:
Pendant-Pendant Sums, where the sum pendant is the summation of a set of contiguous pendant summands,
Colored-Pendant Sums, where the sum pendant is the summation of a set of contiguous by color in a group pendant summands
Indexed-Pendant Sums, where the sum pendant is the summation of a set of contiguous by index in a group pendant summands
Code
import mathimport randomfrom random import choicesimport numpy as npimport pandas as pdfrom pandas import Series, DataFrame# Plotlyimport plotlyfrom plotly.offline import iplot, init_notebook_mode import plotly.graph_objs as goimport plotly.express as pximport plotly.figure_factory as ffplotly.offline.init_notebook_mode(connected =False)import utils_loom as uloomimport utils_khipu as ukhipuimport qollqa_chuspa as qcfrom collections import Counterfrom utils_math import get_statistics
do_print =Falsefor aKhipu in all_khipus: pendant_cords = aKhipu.pendant_cords()for cord in pendant_cords[:-2]: next_cord = pendant_cords[pendant_cords.index(cord)+1] next_next_cord = pendant_cords[pendant_cords.index(next_cord)+1] A = cord.knotted_value B = next_cord.knotted_value C = next_next_cord.knotted_value A_name = cord.pendant_name B_name = next_cord.pendant_name C_name = next_next_cord.pendant_name non_trivial_values =all((x%10)!=0and (x!=1) for x in [A, B, C]) at_least_one_non_trivial_product =max([A,B,C]) >25 multiplier_exists = ((A==B*C) or (B==A*C) or (C==A*B))if (non_trivial_values and at_least_one_non_trivial_product and multiplier_exists):if do_print: print(f"Found multiplier: {aKhipu.kfg_name()}{A_name}={A}, {B_name}={B}, {C_name}={C}")
Code
do_print =Falsefor aKhipu in all_khipus: pendant_cords = aKhipu.pendant_cords()for cord in pendant_cords[:-2]: next_cord = pendant_cords[pendant_cords.index(cord)+1] thiscords_subs = cord.subsidiary_cords A = cord.knotted_value B = next_cord.knotted_valuefor C_cord in thiscords_subs: C = C_cord.knotted_value C_name = C_cord.pendant_name non_trivial_values =all((x%10)!=0and (x!=1) for x in [A, B, C]) at_least_one_non_trivial_product =max([A,B,C]) >25 multiplier_exists = ((A==B*C) or (B==A*C) or (C==A*B))if (non_trivial_values and at_least_one_non_trivial_product and multiplier_exists):if do_print: print(f"Found multiplier: {aKhipu.kfg_name()}{A_name}={A}, {B_name}={B}, {C_name}={C}")
2. Case Studies
Now that we have an idea of what an Equal Sum is, lets look at some examples.
2.1. Case Study 1 - KH0258 - Sum Arrangements with Mixed Verso/Recto Attachments
An obvious use of Equal Sums would be to indicate a distinction between moieties as outlined by Manuel Medrano in his Santa Valley Khipu article using mixed Verso/Recto attachments. A simple example might be to ensure that the two moeities contributed equally. Statistics, confirm that Equal Sums do often associate with mixed Verso/Recto attachments. Despite 27% of the KFG database lacking attachment information, a search of the KFG database reveals several candidate khipus with Equal Sums using mixed Verso/Recto attachments.
KH0258 serves as an example. KH0258, a Chachapoyas khipu, has a left-hand section of all Verso cords, followed by right-hand section of all Recto cords, spanning groups 13 to 31. As you can see the main action is in group 7 and group 12, just before the transition from verso to recto.
New data visualization approaches, adapted from the algorithms of map label placement (too many labels, not enough space) now enable direct overlay of summations on khipus. These summation drawings are, in-effect, X-rays that reveal the khipuâs âinternalâ structure. In the diagram below, Equal Sums are highlighted in yellow, and MultiSummands, those cords involved in more than one sum relationship, are highlighted in green.
Examine g12p2 which has a value of 218 and sums 17 verso cords on the left and 14 recto cords on the right.
Click on image for a larger view
2.1. Case Study 1 - KH0258 - Sum Arrangements with Mixed Verso/Recto Attachments
An obvious use of Equal Sums would be to indicate a distinction between moieties as outlined by Manuel Medrano in his Santa Valley Khipu article using mixed Verso/Recto attachments. A simple example might be to ensure that the two moeities contributed equally. Statistics shown below, confirm that Equal Sums do often associate with mixed Verso/Recto attachments. Despite 27% of the KFG database lacking attachment information, a search of the KFG database reveals several candidate khipus with Equal Sums using mixed Verso/Recto attachments.
KH0258 serves as an example. KH0258, a Chachapoyas khipu, has a left-hand section of all Verso cords, followed by right-hand section of all Recto cords, spanning groups 13 to 31. As you can see the main action is in group 7 and group 12, just before the transition from verso to recto.
New data visualization approaches, adapted from the algorithms of map label placement (too many labels, not enough space) now enable direct overlay of summations on khipus. These summation drawings are, in-effect, X-rays that reveal the khipuâs âinternalâ structure. In the diagram below, Equal Sums are highlighted in yellow, and MultiSummands, those cords involved in more than one sum relationship, are highlighted in green.
Examine g12p2 which has a value of 218 and sums 17 verso cords on the left and 14 recto cords on the right.
Click on image for a larger view
Code
do_print =Falsenum_non_matching_sets =0num_matching_sets =0for index, row in equal_sums_relations_df.iterrows(): kfg_name = row['kfg_name'] khipu = khipu_dict[kfg_name] left_handed_summands = khipu.cords_from_sum_string(row['left_handed_summand_string']) right_handed_summands = khipu.cords_from_sum_string(row['right_handed_summand_string']) left_handed_attachments = [cord.attachment for cord in left_handed_summands] right_handed_attachments = [cord.attachment for cord in right_handed_summands]ifnot (any([x =='U'for x in left_handed_attachments]) orany([x =='U'for x in right_handed_attachments])): num_matching_sets +=1if (set(left_handed_attachments) !=set(right_handed_attachments)): num_non_matching_sets +=1 sum_cord = khipu.find_cord_named(row['sum_cord_name']) sum_group_name = sum_cord.group_name sum_value = sum_cord.knotted_valueif do_print: print(f"{kfg_name} - {sum_group_name}:{sum_value} - {len(left_handed_attachments)} != {len(right_handed_attachments)}")#if do_print: # print(f"Percent of Equal Sums with non matching attachments: {uloom.percent_info(num_non_matching_sets, len(equal_sums_relations_df))}")
2.2. Case Study 2 - KH0696
Our second case study of an equal cord is KH0696, a small khipu of 38 pendants that has been well-studied by most affiliates of the KhipuFieldGuide including the lead author. We just saw, in KH0258, a case of Verso cords then Recto cords. Once again, the layout here is similar, and it is near these Verso/Recto boundaries that the interesting action occurs.
KH0696 has common arithmetic âsignsâ such as one white Equal Sum cord, g4p1, serving as a loop pendant. Letâs examine this Equal Sum cord and see what it tells us.
Click on image for a larger view
2.2.1. G4P1
This khipu has an equality cord, g4p1 (weâll call it T), which is equal to the left-handed sum of all the pendant cords that preceed it, and the sum of two cords on its right g5p1:68 and g5p2:81.
Examine g5p1:68. Its summands span the Center of the khipu â g1p14 through g3p2. Thereâs a span of pendant to the Left of this pendant span and a span of pendants to the Right.
Click on image for a larger view
Let L(Left) be the sum of the pendants between p1 â p12 (g1p1 to g1p12). (12 cords) Let LK be the value of the pendant just to the right of Lp13 (g1p13). (1 cord) Let C(Center) be the sum of the pendants between p14 to p25 (g1p14 to g3p2). (12 cords) This is also the value of right-hand summand g5p1. Let RK be the value of the pendant preceeding Rp26(g3p3). (1 cord) Let R(Right) be the sum of the pendants p27 â p31 (g3p4 to g3p8)(5 cords)
You can now see how double-entry accounting might be implemented in a khipu with the left, center, and right summands as the equity, assets, and liabilities, and individual cords representing accounts such as peanuts, peppers, potatoes, etc.
But wait, thereâs more! Examination of the white pendant cord groups g4 and g5 by Karen Thompson reveals that they are crosstab sums of information from the Left, Center, and Right summands.
g4p1:149 is a crosstab sum of (L:51 + LK:6) + C:68 + (RK:7 + R:17)
g5p1:68 is a crosstab sum of C:68
g5p2:81 is a crosstab sum of (L:51 + LK:6) + (RK:7 + R:17). This elegant result derives from C = L + R and g5p2 = C + LK + RK
g5p3:33 is a crosstab sum of g1p3 to g1p12 - note that g5p3:33 and the next cord g5p4:8 are colored Brown, not White.
g5p4:8 + g5p5:27 is a crosstab sum of (L:51 + R:17) - g5p3:33
g5p6:13 is a crosstab sum of LK:6 + RK:7
This interpretation is strong for KH0696 because the overlapping relations produce a specific three-part decomposition and crosstab structure. However, the existence of an Equal Sum alone does not establish that every such Equal Sum encodes a similar accounting pattern.
2.2.2 Khipus similar to KH0696
Letâs continue to examine khipus with similar equal sums. First lets find all pendant-pendant equal sums, where one of the handed sums has 2 summands and the other is >= 4 summands.
Khipus with One Equal Sum, With # Summands == 2, And # Other Side Summands >= 4:
Unfortunately, none of these khipus have the same double-entry accounting pattern we just reviewed. However, when we expand the search to two Equal sums, we find a similar example, KH0447, whose second Equal Sum Cord g9p4 has a similar pattern:
Click on image for a larger view
As we can see from the Equal Sums histogram below, khipus with multiple equal sums exist. How might that be used to encode information?
Code
do_debug =Falseif do_debug: ak001 = khipu_dict['KH0696']def pendant_cord_sum_range(aKhipu, startcordname, endcordname):returnsum([theCord.knotted_value for theCord in aKhipu.find_pendant_cord_range(startcordname, endcordname)])print(f"L: {pendant_cord_sum_range(ak001, 'g1p1', 'g1p12')=}")print(f"Lk: {pendant_cord_sum_range(ak001, 'g1p13', 'g1p13')=}")print(f"C: {pendant_cord_sum_range(ak001, 'g1p14', 'g3p2')=}")print(f"Rk: {pendant_cord_sum_range(ak001, 'g3p3', 'g3p3')=}")print(f"R: {pendant_cord_sum_range(ak001, 'g3p4', 'g3p8')=}")print(f"{51+6+68+7+17=}\n")# print("57+24 must equal 13+68")# ak001 = khipu_dict['KH0696']# pendant_cords = ak001.pendant_cords()# for cord in pendant_cords:# print(f"{cord.pendant_name=} {cord.group_name=}")
2.2.1. G4P1
This khipu has an equality cord, g4p1 (weâll call it T), which is equal to the left-handed sum of all the pendant cords that preceed it, and the sum of two cords on its right g5p1:68 and g5p2:81.
Examine g5p1:68. Its summands span the Center of the khipu â g1p14 through g3p2. Thereâs a span of pendant to the Left of this pendant span and a span of pendants to the Right.
Let L(Left) be the sum of the pendants between p1 â p12 (g1p1 to g1p12). (12 cords) Let LK be the value of the pendant just to the right of Lp13 (g1p13). (1 cord) Let C(Center) be the sum of the pendants between p14 to p25 (g1p14 to g3p2). (12 cords) This is also the value of right-hand summand g5p1. Let RK be the value of the pendant preceeding Rp26(g3p3). (1 cord) Let R(Right) be the sum of the pendants p27 â p31 (g3p4 to g3p8)(5 cords)
\(51 = L \Leftarrow \displaystyle\sum_{g_1 p_1}^{g_1 p_12}\)
\(6 = L_K \Leftarrow {g_1 p_13}\)
\(68 = C \Leftarrow \displaystyle\sum_{g_1 p_14}^{g_3 p_2}\)
\(7 = R_K \Leftarrow {g_3 p_3}\)
\(17 = R \Leftarrow \displaystyle\sum_{g_3 p_4}^{g_3 p_8}\)
We know for the left-handed summands: L:51 + LK:6 + C:68 + Rk:7 + R:17 = T:149
We also know that for the two right-handed summands: T:149 = g5p1:68 + g5p2:81 g5p1:68 = C:68 g5p2:81 = LK:6 + C:68 + RK:7
This is an example of how double-entry accounting might be implemented in a khipu with the left, center, and right summands as the equity, assets, and liabilities, and individual cords representing accounts such as peanuts, peppers, potatoes, etc.
But wait, thereâs more! Examination of the white pendant cord groups g4 and g5 by Karen Thompson reveals that they are crosstab sums of information from the Left, Center, and Right summands.
g4p1:149 is a crosstab sum of (L:51 + LK:6) + C:68 + (RK:7 + R:17)
g5p1:68 is a crosstab sum of C:68
g5p2:81 is a crosstab sum of (L:51 + LK:6) + (RK:7 + R:17). This elegant result derives from C = L + R and g5p2 = C + LK + RK
g5p3:33 is a crosstab sum of g1p3 to g1p12
g5p4:8 + g5p5:27 is a crosstab sum of (L:51 + R:17) - g5p3:33
g5p6:13 is a crosstab sum of LK:6 + RK:7
2.2.2 Khipus similar to KH0696
Letâs continue to examine khipus with similar equal sums. First lets find all pendant-pendant equal sums, where one of the handed sums is 2 and the other is >= 4.
Unfortunately, none of these khipus have the same double-entry accounting pattern we just reviewed. However, when we expand the search to two Equal sums, we find a similar example, KH0447, whose second Equal Sum Cord g9p4 has a similar pattern:
Click on image for a larger view
As we can see from the Equal Sums histogram below, khipus with multiple equal sums exist. How might that be used to encode information?
2.3. Case Study 3 - KH0232 - Pyramid Sum Arrangements
A look at a summap displays how equal sums work. In a summap, khipu pendant cords are drawn, abstractly as columns, from left to right in the conventional order. Then a row at a time, based on the sum cord index/ordinal, a sum relationship is drawn.
Below is the summap of KH0232. Equal Sums are indcated by a yellow field. MultiSummands, those cords used as summands by more than one sum relationship, are overlaid with a green field.
Click on image for a larger view
Note especially, the Equal Sum cords p32 through p39 in the white middle #7 group. This khipu exhibits classic summation fieldmarks. As noted, in Medrano and Khoslaâs article, many of the sums totals lie on groups starting with a white cord. The summands are marked by figure-eight knot boundary markers as noted in Figure 8 Knots with Ascher Summations.
This khipu exhibits what we would expect of equal sumâs occuring in khipusâŠ
The sums occur in the middle, there being more opportunities for BOTH left and right handed sums in the middle, than on the edges.
The sums increase in the middle.
These khipus exhibit a âpyramidalâ arrangement of sums, with the maximum sum value being roughly in the middle, by building up sums from both sides, towards the center. It is as if the left third of the khipu and the right third were independent khipus that were then tied together with a middle khipu with the additions. In fact, Ascherâs notes for KH0232 are quite intriguing on this aspect.
2.4. Case Study 4 - KH0057 - MultiSummands and Waterfall Sum Arrangements
This khipu exhibits a âwaterfallâ arrangement of sums. In this case, for example, the longest path is [âp1â, âp27â, âp35â, âp51â, âp57â]. P1 the final sum, and contains as it summands p27, which in turn contains as it summands p35 âŠ. all the way to p57. Waterfall khipus tend to have the biggest sum be at p1 or close to that location.
Although waterfalls and pyramid arrangements are visually different, it could be argued that they are topologically similar, and the visual architecture is dependent on the khipukamayoq. We will return to this below.
3. Exploratory Data Analysis
3.1 Database
This study is based on 711 khipus contained in the Khipu Field Guide.
The database is highly heterogenous, and consists of everything from âsheep herderâ khipus to the 8 meter long suspected Bolivian khipu KH0082. However, the database also contains anomalous khipus such as Canuto khipus or khipus consisting of solely one cord. Many of the khipus show broken cords, unmeasured values such as spin or cord attachment, etc. Consequently, we should expect large standard deviations in any statistic we measure. An overview of the database quality is available at the âCompleteness/Anomalousâ table at the Building the KFG Database page
pps_fieldmark = FieldmarkPendantPendantSum()cps_fieldmark = FieldmarkColoredPendantSum()ips_fieldmark = FieldmarkIndexedPendantSum()equal_sums_fieldmark = FieldmarkEqualSums()pps_fieldmark_df = pps_fieldmark.relations_df()cps_fieldmark_df = cps_fieldmark.relations_df()ips_fieldmark_df = ips_fieldmark.relations_df()equal_sums_fieldmark_df = equal_sums_fieldmark.relations_df() pps_equal_sum_dict = {aKhipu.kfg_name(): pps_fieldmark.num_equal_sums(aKhipu.kfg_name()) for aKhipu in all_khipus}cps_equal_sum_dict = {aKhipu.kfg_name(): cps_fieldmark.num_equal_sums(aKhipu.kfg_name()) for aKhipu in all_khipus}ips_equal_sum_dict = {aKhipu.kfg_name(): ips_fieldmark.num_equal_sums(aKhipu.kfg_name()) for aKhipu in all_khipus}pps_equal_sum_khipus = {aKhipu for aKhipu in all_khipus if pps_equal_sum_dict[aKhipu.kfg_name()] >0}cps_equal_sum_khipus = {aKhipu for aKhipu in all_khipus if cps_equal_sum_dict[aKhipu.kfg_name()] >0}ips_equal_sum_khipus = {aKhipu for aKhipu in all_khipus if ips_equal_sum_dict[aKhipu.kfg_name()] >0}
matching_khipus_df = equal_sum_fieldmark_df[equal_sum_fieldmark_df['num_equal_sums']>0] # type: ignorenum_equal_sum_khipus =len(matching_khipus_df) print(f"Number of khipus with at least 1 Equal Sum: {uloom.percent_info(num_equal_sum_khipus,len(all_khipus))}") at_least_4_matching_khipus_df = matching_khipus_df[matching_khipus_df['num_equal_sums']>=4]num_4_equal_sum_khipus =len(at_least_4_matching_khipus_df) #print(f"Number of khipus with at least 4 equal sums: {num_4_equal_sum_khipus}") at_least_10_matching_khipus_df = matching_khipus_df[matching_khipus_df['num_equal_sums']>=10]#print(f"Number of khipus with at least 10 equal sums: {len(at_least_10_matching_khipus_df)}") #matching_khipus_df.head(3)#print()num_all_khipu_equal_sums =len(equal_sum_relations_df) # type: ignorenum_pps_khipu_equal_sums =len(equal_sum_relations_df[equal_sum_relations_df['fieldmark_name']=="pendant_pendant_sum"]) # type: ignorenum_cps_khipu_equal_sums =len(equal_sum_relations_df[equal_sum_relations_df['fieldmark_name']=="colored_pendant_sum"]) # type: ignorenum_ips_khipu_equal_sums =len(equal_sum_relations_df[equal_sum_relations_df['fieldmark_name']=="indexed_pendant_sum"]) # type: ignoreprint(f"Number of All Equal Sums: {num_all_khipu_equal_sums}")print(f"Number of Pendant-Pendant Equal Sums: {uloom.percent_info(num_pps_khipu_equal_sums, num_all_khipu_equal_sums)}") print(f"Number of Colored-Pendant Equal Sums: {uloom.percent_info(num_cps_khipu_equal_sums, num_all_khipu_equal_sums)}")print(f"Number of Indexed-Pendant Equal Sums: {uloom.percent_info(num_ips_khipu_equal_sums, num_all_khipu_equal_sums)}")# Build a histogram of the number of equal sums per khipu using plotly histogramdef num_khipus_with_equal_sums(min_num_equal_sums):returnlen(equal_sum_fieldmark_df[equal_sum_fieldmark_df['num_equal_sums'] == min_num_equal_sums]) # type: ignorenum_equal_sums_histogram = equal_sum_fieldmark_df['num_equal_sums'].value_counts().sort_index() # type: ignoremax_num_equal_sums = num_equal_sums_histogram.index[-1]num_equal_sums = [i for i inrange(0, max_num_equal_sums +1)]num_khipus_with_equal_sums = [num_khipus_with_equal_sums(num_sums) for num_sums in num_equal_sums] # type: ignorenum_khipus_with_equal_sums_df = pd.DataFrame({'num_equal_sums': num_equal_sums, 'num_khipus': num_khipus_with_equal_sums})fig = (px.bar(num_khipus_with_equal_sums_df, x="num_equal_sums", y="num_khipus", log_y=True, title="Histogram of Number of Equal Sums per Khipu") .update_layout(xaxis_title="Number of Equal Sums", yaxis_title="Number of Khipus (log scale)", height=600, font=dict(family="ETBookOT")) .show())
Number of khipus with at least 1 Equal Sum: 27% (194 of 711)
Number of All Equal Sums: 2084
Number of Pendant-Pendant Equal Sums: 59% (1228 of 2084)
Number of Colored-Pendant Equal Sums: 33% (694 of 2084)
Number of Indexed-Pendant Equal Sums: 8% (162 of 2084)
3.2 What are Common Fieldmarks Associated with Equal Sums
Code
# Useful functions to collect the statistics about a khipu's equal sums for a given fieldmarkdef equal_color_map_df(aKFGName, aFieldmark): theKhipu = khipu_dict[aKFGName] aFieldmark_df = aFieldmark.relations_df() equal_sums_df = equal_sums_fieldmark.relations_df() equal_relations_df = equal_sums_df[equal_sums_df['kfg_name'] == aKFGName]print(len(equal_relations_df)) khipu_records = []for index, aEqualSumRelation in equal_relations_df.iterrows(): left_handed_summand_string = aEqualSumRelation['left_handed_summand_string'] right_handed_summand_string = aEqualSumRelation['right_handed_summand_string'] left_handed_summand_string = aEqualSumRelation['left_handed_summand_string'] right_handed_summand_string = aEqualSumRelation['right_handed_summand_string'] left_handed_cords = [] right_handed_cords = [] if left_handed_summand_string andisinstance(left_handed_summand_string, str) andlen(left_handed_summand_string) >0: left_handed_cords = aFieldmark.cords_from_sum_string(theKhipu, left_handed_summand_string)if right_handed_summand_string andisinstance(right_handed_summand_string, str) andlen(right_handed_summand_string) >0: right_handed_cords = aFieldmark.cords_from_sum_string(theKhipu, right_handed_summand_string) left_handed_cord_colors = [cord.main_color() for cord in left_handed_cords]# left_counter = Counter(left_handed_cord_colors)#count_left_handed_cords_colors = ", ".join([f"{color}({count})" for color, count in left_counter.items()]) num_left_handed_cord_colors =len(set(left_handed_cord_colors)) right_handed_cord_colors = [cord.main_color() for cord in right_handed_cords]# right_counter = Counter(right_handed_cord_colors)#count_right_handed_cords_colors = ", ".join([f"{color}({count})" for color, count in right_counter.items()]) num_right_handed_cord_colors =len(set(right_handed_cord_colors)) khipu_records.append({'kfg_name':aEqualSumRelation['kfg_name'],'sum_cord_name':aEqualSumRelation['sum_cord_name'],'left_handed_summand_string':left_handed_summand_string,'right_handed_summand_string':right_handed_summand_string,'num_left_handed_cord_colors':num_left_handed_cord_colors,'num_right_handed_cord_colors':num_right_handed_cord_colors,'left_handed_cord_colors':','.join(left_handed_cord_colors),'right_handed_cord_colors':','.join(right_handed_cord_colors),'num_recto_cords':theKhipu.num_recto_cords(),'num_verso_cords':theKhipu.num_verso_cords(), }) equal_color_map_df = pd.DataFrame(khipu_records)return equal_color_map_dfdef equal_sum_statistics(aKFGName, aFieldmark): aKhipu = khipu_dict[aKFGName] equal_sum_cord_names = aFieldmark.equal_sums(aKFGName)iflen(equal_sum_cord_names) ==0:returnNone equal_sum_cords = [aKhipu[aCordName] for aCordName in equal_sum_cord_names] last_sum_cord_ordinal =int((ukhipu.sort_cord_names_by_ordinal(equal_sum_cord_names)[-1])[1:]) equal_sum_cord_values = [aCord.knotted_value for aCord in equal_sum_cords] similar_cord_values_counter = [(value, count) for value,count in Counter(equal_sum_cord_values).most_common() if count >1] num_similar =sum([count for value, count in similar_cord_values_counter]) percent_similar =100.0*num_similar/len(equal_sum_cord_values) cord_deltas = [0] + [equal_sum_cord_values[i] - equal_sum_cord_values[i-1] for i inrange(1, len(equal_sum_cord_values))] similar_cord_deltas_counter = [(value, count) for value,count in Counter(cord_deltas).most_common() if count >1] num_similar_deltas =sum([count for value, count in similar_cord_deltas_counter]) percent_similar_deltas =100.0*num_similar_deltas/len(cord_deltas) cord_val_stats = get_statistics(equal_sum_cord_values) min_cord_value = cord_val_stats['min'] mean_cord_value = cord_val_stats['mean'] max_cord_value = cord_val_stats['max'] stddev_cord_value = cord_val_stats['stddev'] value_spread = cord_val_stats['spread'] cord_delta_stats = get_statistics(cord_deltas) min_cord_delta = cord_delta_stats['min'] mean_cord_delta = cord_delta_stats['mean'] max_cord_delta = cord_delta_stats['max'] stddev_cord_delta = cord_delta_stats['stddev'] delta_spread = cord_delta_stats['spread'] num_banded_groups = aKhipu.num_banded_groups() num_seriated_groups = aKhipu.num_seriated_groups() more_seriated = num_seriated_groups > num_banded_groups has_mixed_attachments = aKhipu.has_mixed_attachments()return {'kfg_name': aKhipu.kfg_name(),'fieldmark_name': aFieldmark.shortname, # 'pendant_pendant_sums' or 'colored_pendant_sums'num_pendant_cords': aKhipu.num_pendant_cords(),'num_equal_sums': len(equal_sum_cord_values),'last_sum_cord_ordinal': last_sum_cord_ordinal, 'cord_names': f"{equal_sum_cord_names}", #Convert list to string'cord_values': f"{equal_sum_cord_values}", #Convert list to string'similar_cord_values': similar_cord_values_counter,'num_similar': num_similar,'percent_similar': percent_similar,'min_cord_value': min_cord_value, 'mean_cord_value': mean_cord_value, 'max_cord_value': max_cord_value, 'stddev_cord_value': stddev_cord_value, 'value_spread': value_spread,'cord_deltas': f"{cord_deltas}", #Convert list to string'similar_cord_deltas': similar_cord_deltas_counter,'num_similar_deltas': num_similar_deltas,'percent_similar_deltas': percent_similar_deltas,'min_cord_delta': min_cord_delta, 'mean_cord_delta': mean_cord_delta,'max_cord_delta': max_cord_delta, 'stddev_cord_delta': stddev_cord_delta, 'delta_spread': delta_spread,'num_seriated_groups':num_seriated_groups,'num_banded_groups':num_banded_groups,'more_seriated':more_seriated, 'has_mixed_attachments': has_mixed_attachments, } def print_equal_sum_stats(aStatsRecord):print(f"Khipu: {aStatsRecord['kfg_name']} - Fieldmark: {aStatsRecord['fieldmark_name']} - # Pendant Cords: {aStatsRecord['num_pendant_cords']}")print(f"\tNumber of Equal Sums: {aStatsRecord['num_equal_sums']}")print(f"\tCord Names: {aStatsRecord['cord_names']}")print(f"\tCord Values: {aStatsRecord['cord_values']}")print(f"\tMin, Mean, Max Cord Value: {aStatsRecord['min_cord_value']:.1f} - {float(aStatsRecord['mean_cord_value']):.1f} - {aStatsRecord['max_cord_value']:.1f} +/- {aStatsRecord['stddev_cord_value']:.1f} Spread:({aStatsRecord['value_spread']:.2f})")print(f"\tSimilar Delta Values: {aStatsRecord['similar_cord_values']}")print(f"\tSimilar Delta Values: {aStatsRecord['num_similar']}:({aStatsRecord['percent_similar']:.0f}%) - {aStatsRecord['similar_cord_values']}")print(f"\tCord Deltas: {aStatsRecord['cord_deltas']}")print(f"\tMin, Mean, Max Cord Delta: {aStatsRecord['min_cord_delta']:.1f} - {aStatsRecord['mean_cord_delta']:.1f} - {aStatsRecord['max_cord_delta']:.1f} +/- {aStatsRecord['stddev_cord_delta']:.1f} Spread:({aStatsRecord['delta_spread']:.2f})")print(f"\tMore Seriated: {aStatsRecord['more_seriated']}, # Seriated Groups = {aStatsRecord['num_seriated_groups']}, # Banded Groups = {aStatsRecord['num_banded_groups']})")print(f"\tMixed Attachments: {aStatsRecord['has_mixed_attachments']}")equal_sums_fieldmark_df = equal_sums_fieldmark.fieldmark_df() matching_khipus_df = equal_sums_fieldmark_df[equal_sums_fieldmark_df['num_equal_sums']>0]def build_equal_sums_dict(): matching_khipus_df.sort_values(by='num_equal_pps_sums', ascending=False, inplace=True) pps_matching_khipus = matching_khipus_df['kfg_name'].tolist() matching_khipus_df.sort_values(by='num_equal_cps_sums', ascending=False, inplace=True) cps_matching_khipus = matching_khipus_df['kfg_name'].tolist() pps_equal_sum_stats =dict()for kfg_name in pps_matching_khipus:if stats := equal_sum_statistics(kfg_name, pps_fieldmark): pps_equal_sum_stats[kfg_name] = stats cps_equal_sum_stats =dict()for kfg_name in cps_matching_khipus:if stats := equal_sum_statistics(kfg_name, cps_fieldmark): cps_equal_sum_stats[kfg_name] = statsreturn (pps_equal_sum_stats, cps_equal_sum_stats)(pps_equal_sums_stats, cps_equal_sums_stats) = build_equal_sums_dict()
# Create Cosine Similarity Matriximport utils_pandas as upanda cosine_sim_matrix = upanda.CosineSimilarityMatrix(augmented_fieldmark_df, start_column="equal_sums", start_row="KH0239")sorted_df = cosine_sim_matrix.sort(sort_columns =True, sort_rows =True)sorted_columns = sorted_df.columns.tolist()do_debug =Falseif do_debug: print(f"Fieldmarks sorted by Closest Match using Cosine Similarity = {nl_char}{uloom.multiline(sorted_columns, split_char=',', continuation_char=nl_char)}")fig = (px.imshow(sorted_df.to_numpy().tolist(), labels=dict(x="Fieldmark", y="Khipu Name", ), x=sorted_df.columns, y=fieldmark_KFG_Names, width=944, height=2000, aspect="auto") .update_coloraxes(showscale=False) .update_layout( title='Fieldmark Features - Sorted by Cosine Similarity - Hover over line for more info', xaxis=dict(tickangle=270), xaxis_nticks=5000, font=dict(family="ETBookOT")) .show())
Because so few khipus have equal sums, we have to read this diagram carefully. As you see above recto vs verso cords light up yellow, as do percent_z_knots, indicating moeity information is present in khipus with Equal Sum Cords. We will return to this thought below.
3.3 Equal Sums by Number of Pendant Cords
As might be expected, the number of equal sums per khipu is a good indicator of the complexity of the khipu and vice versa.
Code
# Make a plotly scatter plot of the number of equal sums per khipu vs the number of pendant cordsmatching_kfg_names = matching_khipus_df['kfg_name'].tolist()num_equal_sums = [matching_khipus_df[matching_khipus_df['kfg_name']==kfg_name].num_equal_sums.tolist()[0] for kfg_name in matching_kfg_names]num_cords = [khipu_dict[kfg_name].num_pendant_cords() for kfg_name in matching_kfg_names]df = pd.DataFrame({'num_cords': num_cords, 'num_equal_sums': num_equal_sums, 'kfg_name': matching_kfg_names})fig = (px.scatter(df, x=num_cords, y=num_equal_sums, log_y=True, log_x=True, hover_data=['kfg_name', 'num_cords', 'num_equal_sums']) .update_layout(title="Number of Equal Sums vs Number of Pendant Cords", xaxis_title="Number of Pendant Cords (log scale)", yaxis_title="Number of Equal Sums (log scale)", height=600, font=dict(family="ETBookOT")) .show())
3.4 Equal Sums by Mean Pendant Cord Value
Letâs compare Equal Sum khipus by mean cord value of non-zero pendant cord:
Code
non_zero_cord_stats = []all_the_equal_sum_khipus = pps_equal_sum_khipus.union(cps_equal_sum_khipus).union(ips_equal_sum_khipus)min_node_size =6for aKhipu in all_khipus: is_equal_sum_khipu ="equal_sum"if (aKhipu in all_the_equal_sum_khipus) else"non_equal_sum" num_equal_sums = pps_equal_sum_dict[aKhipu.kfg_name()] + cps_equal_sum_dict[aKhipu.kfg_name()] + ips_equal_sum_dict[aKhipu.kfg_name()]if is_equal_sum_khipu =="non_equal_sum": node_size=min_node_size else: node_size =max(min_node_size,num_equal_sums) khipu_record = {'kfg_name': aKhipu.kfg_name(),'mean_non_zero_cord_value': aKhipu.mean_non_zero_pendant_cord_value(),'num_non_zero_pendant_cords': len(aKhipu.non_zero_pendant_cord_values()),'is_equal_sum_khipu': is_equal_sum_khipu,'num_equal_sums': num_equal_sums,'node_size': node_size, } non_zero_cord_stats.append(khipu_record)non_zero_cord_stats_df = pd.DataFrame(non_zero_cord_stats)plot_title =f"{len(all_khipus)} Khipus by # Non-Zero Pendant Cords vs. Mean Value Non-Zero Pendant Cords / Size=# Equal Sums"fig = (px.scatter(non_zero_cord_stats_df, x="num_non_zero_pendant_cords", y="mean_non_zero_cord_value", log_y=True, log_x=True, color="is_equal_sum_khipu", color_discrete_sequence=["black", "red"], size="node_size", hover_name='kfg_name', hover_data=['num_non_zero_pendant_cords', 'mean_non_zero_cord_value', 'num_equal_sums'], title=plot_title, width=944, height=944) .update_layout(showlegend=True, yaxis_title="Mean Non Zero Pendant Cord_value (Log Scale)", xaxis_title="# Pendant_Cords(Log Scale)", font=dict(family="ETBookOT")) .update(layout_coloraxis_showscale=True).show() )
The above graphic illuminates how clearly special Equal Sum khipus are - they appear in larger (by # of non-zero pendant cord) khipus (above 25 cords), and they rarely exceed 500 in average cord value. This graphic fits with the above cosine similarity fieldmark sorting, which indicates the number of pendant cords is a predictor of where there is a high number of Equal Sums.
Code
from statistics import meandef equal_sum_cord_stats(aKhipu, aFieldmark): num_fieldmark_sums = aFieldmark.num_sums(aKhipu.kfg_name()) equal_sum_cord_names = aFieldmark.equal_sums(aKhipu.kfg_name())iflen(equal_sum_cord_names) ==0:returnNone equal_sum_cords = [aKhipu[aCordName] for aCordName in equal_sum_cord_names] equal_sum_cord_values = [aCord.knotted_value for aCord in equal_sum_cords] min_cord_value =min(equal_sum_cord_values) mean_cord_value = mean(equal_sum_cord_values) max_cord_value =max(equal_sum_cord_values) max_cord_index = equal_sum_cord_values.index(max_cord_value) max_cord_location =float(equal_sum_cord_names[max_cord_index][1:])/float(aKhipu.num_pendant_cords()) max_sum_path_length, path_sum_names = aFieldmark.maximum_sum_path(aKhipu.kfg_name()) pendant_path_sum_names = [aKhipu.find_cord_named(sum_name).pendant_name for sum_name in path_sum_names] longest_path =",".join(pendant_path_sum_names) final_ordinal =int(pendant_path_sum_names[-1][1:]) normalized_final_ordinal =float(final_ordinal)/float(aKhipu.num_pendant_cords()) mean_num_summands = mean([mean(aFieldmark.num_summands(aKhipu.kfg_name(), aCordName)) for aCordName in equal_sum_cord_names])return {'kfg_name': aKhipu.kfg_name(),'fieldmark_name': aFieldmark.shortname, # 'pendant_pendant_sums' or 'colored_pendant_sums'num_pendant_cords': aKhipu.num_pendant_cords(),'num_fieldmark_sums': num_fieldmark_sums,'num_equal_sums': len(equal_sum_cord_values),'cord_names': f"{equal_sum_cord_names}", #Convert list to string'cord_values': f"{equal_sum_cord_values}", #Convert list to string'min_cord_value': min_cord_value,'mean_cord_value': round(mean_cord_value,1),'max_cord_value': max_cord_value,'mean_num_summands': round(mean_num_summands,0),'max_sum_path_length': max_sum_path_length,'longest_path': longest_path,'final_ordinal': final_ordinal,'normalized_final_ordinal': normalized_final_ordinal,'normalized_max_cord_location': round(max_cord_location,3), }pps_khipu_equal_sum_cord_stats = [equal_sum_cord_stats(aKhipu, pps_fieldmark) for aKhipu in pps_equal_sum_khipus]pps_khipu_equal_sum_cord_stats_df = pd.DataFrame(pps_khipu_equal_sum_cord_stats)#pps_khipu_equal_sum_cord_stats_df.head()
Code
plot_title ="Khipus by # of Equal Sums vs. Mean Cord Value w/Size=Mean Number of Summands"fig = (px.scatter(pps_khipu_equal_sum_cord_stats_df, x="num_equal_sums", y="mean_cord_value", log_y=True, log_x=True, size="mean_num_summands", color="max_cord_value", labels={"kfg_name": "KFG Name", "num_pendant_cords": "# Pendant Cords","num_equal_sums": "# Equal Sums", "max_sum_path_length": "Max Sum Path Length","mean_cord_value": "Mean Cord Value", "max_cord_value": "Max Cord Value", "mean_num_summands": "Mean # Summands per Equal Sum" }, hover_name='kfg_name', hover_data=['num_pendant_cords', 'num_equal_sums', 'mean_cord_value', 'max_cord_value', 'mean_num_summands'], title=plot_title, width=944, height=944) .update_layout(showlegend=True, yaxis_title="Mean Equal Sum Cord Value (Log Scale)", xaxis_title="Number of Equal Sums (Log Scale)", font=dict(family="ETBookOT")) .update(layout_coloraxis_showscale=True) .show() )
3.5 Equal Sums by Number of Summands (Left vs Right)
fig = (px.histogram(equal_sums_relations_df, x="delta_num_summands", log_y=True, title="Histogram of Deltas of # Summands (# Right Summands - # Left Summands)") .update_layout(font=dict(family="ETBookOT")) .show())
So the majority of Equal Sums have roughly the same number of summands on each side of the equation. The slight right shift in the histogram reflects, perhaps, the same 55%/45% preponderance of right-handed vs left-handed sums witnessed in Medrano and Khoslaâs article. Still, there are a substantial portion of khipus whose delta num_summand values are greater than say 20? Letâs look at the data another way by graphing left vs right summands for all the Equal Sums
Code
#equal_sums_relations_df = equal_sums_fieldmark.relations_df()plot_title ="Equal Sums by # Of Right vs Left Summands (Log Scale) - Size=# Equal Sums - Hover for info"fig = (px.scatter(equal_sums_relations_df, x="num_right_summands", y="num_left_summands", log_y=True, log_x=True, size="total_equal_sums", color="sum_cord_value", labels={"kfg_name": "KFG Name", "sum_cord_name": "Equal Sum Cordname","sum_cord_value": "Equal Sum Cord Value","num_left_summands": "# Left Summands","num_right_summands": "# Right Summands","delta_num_summands": "# Right - Left Summands", }, hover_name='kfg_name', hover_data=['sum_cord_name', 'sum_cord_value', 'num_left_summands', 'num_right_summands', 'delta_num_summands'], title=plot_title, width=944, height=944) .update_layout(showlegend=True, yaxis_title="# Left Summands (Log Scale)", xaxis_title="# Right Summands (Log Scale)", font=dict(family="ETBookOT")) .update(layout_coloraxis_showscale=True) .show() )
Code
asymmetric_equal_sums_df = equal_sums_relations_df[equal_sums_relations_df['abs_delta_num_summands'] >7]print(f"Number of Asymmetric Equal Sums > 7 Summands: {len(asymmetric_equal_sums_df)}")print(f"Number of Asymmetric Equal Sum Khipus > 7 Summands: {len(asymmetric_equal_sums_df['kfg_name'].unique())}")asymmetric_equal_sums_df.sort_values(by='abs_delta_num_summands', ascending=False, inplace=True)top_asymmetric_kfg_names = asymmetric_equal_sums_df.head(50)['kfg_name'].unique().tolist()print(f"{top_asymmetric_kfg_names=}")do_print =Falseif do_print: make_equal_sums_network_table(kfg_names=top_asymmetric_kfg_names)
Number of Asymmetric Equal Sums > 7 Summands: 267
Number of Asymmetric Equal Sum Khipus > 7 Summands: 74
top_asymmetric_kfg_names=['KH0082', 'KH0468', 'KH0068', 'KH0699', 'KH0240', 'KH0601', 'KH0665', 'KH0225', 'KH0143']
The list of interesting asymmetrical equal sums includes our old friend KH0468/UR231 discussed in Medrano and Khosla! So the answer is there can be both kinds of equal sums in evidence.
KFG Name
# Equal Pendant-Pendant Sums
Pendant-Pendant SumMap
# Equal Colored-Pendant Sums
Colored-Pendant SumMap
# Equal Indexed-Pendant Sums
Indexed-Pendant SumMap
KH0068
12
1
KH0082
85
125
26
KH0143
11
1
KH0225
6
1
KH0240
45
59
3
KH0468
39
KH0601
7
1
2
KH0665
2
KH0699
18
15
1
3.6 Equal Sums by Color
First, letâs look at how colors are distributed in the equal sum cords.
Code
# EDA of Equal Sums by Colorkfg_names = equal_sums_relations_df['kfg_name'].to_list()sum_cord_names = equal_sums_relations_df['sum_cord_name'].to_list()cord_search =zip(kfg_names, sum_cord_names)equal_sum_cords = [khipu_dict[kfg_name].find_cord_named(sum_cord_name) for kfg_name, sum_cord_name in cord_search]num_equal_sums =len(equal_sum_cords)equal_sum_colors = [cord.main_color(use_brezine_colors=True) for cord in equal_sum_cords]from collections import Counterequal_sum_colors_counter = Counter(equal_sum_colors)common_colors = [color for color, count in equal_sum_colors_counter.most_common(20)]common_counts = [count for color, count in equal_sum_colors_counter.most_common(20)]from ascher_color import AscherColorbar_colors = { color:AscherColor(color, 0, 0).average_color() for color in common_colors }labels = [f"{c} ({c/num_equal_sums:.0%})"for c in common_counts]title =f"Equal Sum Colors (by % of {num_equal_sums} Equal Sums)"# Use plotly to draw a bar chart of the equal sum colorsimport plotly.express as pxfig = (px.bar( x=common_colors, y=common_counts, text=labels, color=common_colors, color_discrete_map = bar_colors ) .update_layout( title=title, xaxis_title='Color', yaxis_title='Count', font=dict(family="ETBookOT") ) .show() )
White cords predominate in the Equal Sum cords - which is expected but at a percentage of 38% of their peers, compared to 29% of overall pendant-pendant sums.
Next letâs look at the distribution of the number of different colors in a equal sum summand list.
Code
aFieldmark = equal_sums_fieldmarkfull_fieldmark_df = aFieldmark.relations_df()num_left_handed_cord_colors = full_fieldmark_df['num_left_handed_cord_colors'].values.tolist()num_right_handed_cord_colors = full_fieldmark_df['num_right_handed_cord_colors'].values.tolist()counter_left_handed_cord_colors =sorted(Counter(num_left_handed_cord_colors).items(),key=lambda x: x[0])counter_right_handed_cord_colors =sorted(Counter(num_right_handed_cord_colors).items(),key=lambda x: x[0])counter_both_handed_cord_colors =sorted(Counter(num_left_handed_cord_colors+num_right_handed_cord_colors).items(),key=lambda x: x[0])total_x_values = [item[0] for item in counter_both_handed_cord_colors]total_y_values = [item[1] for item in counter_both_handed_cord_colors]total_y_text = [f"{x:.1f} %"for x in100.0*np.cumsum(total_y_values)/np.sum(total_y_values)]fig = (go.Figure(data=[go.Bar(x=total_x_values, y=total_y_values, text = total_y_text)]) .update_layout(title='Total #Colors/Equal Sum (Top of Split Bars is Cumulative Sum % of Summands Colors)', xaxis_title='# of Pendant Cord Colors in Double Sum', yaxis_title='# of Sums W/That # of Colors', font=dict(family="ETBookOT")) .show())
So ~55% of all Equal Sums have only one color and ~75% are two colors or less!
3.7 Equal Sums by Banded vs Seriated
Code
pps_khipus =list(pps_equal_sums_stats.keys())cps_khipus =list(cps_equal_sums_stats.keys())print(len(pps_equal_sums_stats), len(cps_equal_sums_stats))def khipu_group_stats(aKFGName): aKhipu = qc.fetch_khipu(aKFGName) num_banded_groups = aKhipu.num_banded_groups() num_seriated_groups = aKhipu.num_seriated_groups() more_seriated = num_seriated_groups > num_banded_groupsreturn {'kfg_name':aKFGName, 'more_seriated':more_seriated, 'num_seriated_groups':num_seriated_groups, 'num_banded_groups':num_banded_groups}def print_group_stats(aStatsList):for aStats in aStatsList:print(f"Khipu: {aStats['kfg_name']} - More Seriated: {aStats['more_seriated']}, Seriated Groups: {aStats['num_seriated_groups']}, Banded Groups: {aStats['num_banded_groups']} ")pps_group_stats = [khipu_group_stats(kfg_name) for kfg_name in pps_khipus] cps_group_stats = [khipu_group_stats(kfg_name) for kfg_name in cps_khipus]
189 76
Code
pps_num_more_seriated =sum([1for khipu in pps_group_stats if khipu['more_seriated']])pps_group_stats.sort(key=lambda x: (x['more_seriated'], x['num_banded_groups'], x['num_seriated_groups']), reverse=False) percent_str = uloom.percent_info(pps_num_more_seriated, len(pps_group_stats))print(f"For Equal Sum khipus: {percent_str} have more seriated groups/clusters than banded groups/clusters")
For Equal Sum khipus: 78% (147 of 189) have more seriated groups/clusters than banded groups/clusters
Equal sum khipus appear to be predominantly on seriated khipus. But the actual summands do not appear to be seriated. Furthermore in the fieldmark closesness test we did above, color-bands are closely associated with equal sums.
3.8 Equal Sums Association with Recto/Verso Cords - Mixed Attachments
Letâs look at percentages of khipus with mixed attachments (both recto and verso), compared to the general population of overall khipus, pendant-pendant-sum khipus and pendant-pendant sum khipus with Equal Sums:
Code
all_kfg_names = [aKhipu.kfg_name() for aKhipu in all_khipus]the_pps_fieldmark_df = pps_fieldmark.fieldmark_df()the_pps_khipus_df = the_pps_fieldmark_df[the_pps_fieldmark_df['num_sum_cords']>0] pps_kfg_names = ukhipu.kfg_order(the_pps_khipus_df['kfg_name'].tolist())pps_khipus = [qc.fetch_khipu(aKFGName) for aKFGName in pps_kfg_names]pps_sums_dict = {aKhipu.kfg_name(): pps_fieldmark.num_sums(aKhipu.kfg_name()) for aKhipu in all_khipus}pps_equal_sum_dict = {aKhipu.kfg_name(): pps_fieldmark.num_equal_sums(aKhipu.kfg_name()) for aKhipu in all_khipus}equal_khipus = [aKhipu for aKhipu in all_khipus if pps_equal_sum_dict[aKhipu.kfg_name()] >0]equal_kfg_names = [aKhipu.kfg_name() for aKhipu in equal_khipus]all_recto_khipus = {aKhipu.kfg_name(): aKhipu.num_recto_cords() for aKhipu in all_khipus if aKhipu.num_recto_cords() >0}all_verso_khipus = {aKhipu.kfg_name(): aKhipu.num_verso_cords() for aKhipu in all_khipus if aKhipu.num_verso_cords() >0}all_non_attached_khipus = {kfg_name : 0for kfg_name in all_kfg_names ifnot ((kfg_name in all_recto_khipus) or (kfg_name in all_verso_khipus))}all_recto_kfg_names =list(all_recto_khipus.keys())all_verso_kfg_names =list(all_verso_khipus.keys())all_mixed_attachment_kfg_names = [aKhipu.kfg_name() for aKhipu in all_khipus if aKhipu.has_mixed_attachments() ]all_unattached_kfg_names =list(all_non_attached_khipus.keys())print(f"Number of All Sum Khipus: {len(all_kfg_names)}")recto_info = uloom.percent_info(len(all_recto_kfg_names), len(all_kfg_names), rounddigits=2)print(f"Number of All Sum Khipus with Recto Cords: {recto_info}")verso_info = uloom.percent_info(len(all_verso_kfg_names), len(all_kfg_names), rounddigits=2) print(f"Number of All Sum Khipus with Verso Cords: {verso_info}") mixed_attachment_info = uloom.percent_info(len(all_mixed_attachment_kfg_names), len(all_kfg_names), rounddigits=2)print(f"Number of All Sum Khipus with Mixed Cord Attachments: {mixed_attachment_info}")unattached_info = uloom.percent_info(len(all_unattached_kfg_names), len(all_kfg_names), rounddigits=2) print(f"Number of All Sum Khipus with Unknown Cord Attachments: {unattached_info}")print()pps_recto_khipus = {aKhipu.kfg_name(): aKhipu.num_recto_cords() for aKhipu in pps_khipus if aKhipu.num_recto_cords() >0}pps_verso_khipus = {aKhipu.kfg_name(): aKhipu.num_verso_cords() for aKhipu in pps_khipus if aKhipu.num_verso_cords() >0}pps_non_attached_khipus = {kfg_name : 0for kfg_name in equal_kfg_names ifnot ((kfg_name in pps_recto_khipus) or (kfg_name in pps_verso_khipus))}pps_recto_kfg_names =list(pps_recto_khipus.keys())pps_verso_kfg_names =list(pps_verso_khipus.keys())pps_mixed_attachment_kfg_names = [aKhipu.kfg_name() for aKhipu in pps_khipus if aKhipu.has_mixed_attachments() ]pps_unattached_kfg_names =list(pps_non_attached_khipus.keys())print(f"Number of PPS Sum Khipus: {len(pps_kfg_names)}")recto_info = uloom.percent_info(len(pps_recto_kfg_names), len(pps_kfg_names), rounddigits=2)print(f"Number of PPS Sum Khipus with Recto Cords: {recto_info}")verso_info = uloom.percent_info(len(pps_verso_kfg_names), len(pps_kfg_names), rounddigits=2) print(f"Number of PPS Sum Khipus with Verso Cords: {verso_info}") mixed_attachment_info = uloom.percent_info(len(pps_mixed_attachment_kfg_names), len(pps_kfg_names), rounddigits=2)print(f"Number of PPS Sum Khipus with Mixed Cord Attachments: {mixed_attachment_info}")unattached_info = uloom.percent_info(len(pps_unattached_kfg_names), len(pps_kfg_names), rounddigits=2) print(f"Number of PPS Sum Khipus with Unknown Cord Attachments: {unattached_info}")print()equal_recto_khipus = {aKhipu.kfg_name(): aKhipu.num_recto_cords() for aKhipu in equal_khipus if aKhipu.num_recto_cords() >0}equal_verso_khipus = {aKhipu.kfg_name(): aKhipu.num_verso_cords() for aKhipu in equal_khipus if aKhipu.num_verso_cords() >0}equal_non_attached_khipus = {kfg_name : 0for kfg_name in equal_kfg_names ifnot ((kfg_name in equal_recto_khipus) or (kfg_name in equal_verso_khipus))}equal_recto_kfg_names =list(equal_recto_khipus.keys())equal_verso_kfg_names =list(equal_verso_khipus.keys())equal_mixed_attachment_kfg_names = [aKhipu.kfg_name() for aKhipu in equal_khipus if aKhipu.has_mixed_attachments() ]equal_unattached_kfg_names =list(equal_non_attached_khipus.keys())print(f"Number of Equal Sum Khipus: {len(equal_kfg_names)}")recto_info = uloom.percent_info(len(equal_recto_kfg_names), len(equal_kfg_names), rounddigits=2)print(f"Number of Equal Sum Khipus with Recto Cords: {recto_info}")verso_info = uloom.percent_info(len(equal_verso_kfg_names), len(equal_kfg_names), rounddigits=2) print(f"Number of Equal Sum Khipus with Verso Cords: {verso_info}") mixed_attachment_info = uloom.percent_info(len(equal_mixed_attachment_kfg_names), len(equal_kfg_names), rounddigits=2)print(f"Number of Equal Sum Khipus with Mixed Cord Attachments: {mixed_attachment_info}")unattached_info = uloom.percent_info(len(equal_unattached_kfg_names), len(equal_kfg_names), rounddigits=2) print(f"Number of Equal Sum Khipus with Unknown Cord Attachments: {unattached_info}")print()
Number of All Sum Khipus: 711
Number of All Sum Khipus with Recto Cords: 51% (364 of 711)
Number of All Sum Khipus with Verso Cords: 46% (327 of 711)
Number of All Sum Khipus with Mixed Cord Attachments: 26% (188 of 711)
Number of All Sum Khipus with Unknown Cord Attachments: 29% (208 of 711)
Number of PPS Sum Khipus: 410
Number of PPS Sum Khipus with Recto Cords: 55% (224 of 410)
Number of PPS Sum Khipus with Verso Cords: 53% (219 of 410)
Number of PPS Sum Khipus with Mixed Cord Attachments: 34% (141 of 410)
Number of PPS Sum Khipus with Unknown Cord Attachments: 10% (41 of 410)
Number of Equal Sum Khipus: 189
Number of Equal Sum Khipus with Recto Cords: 63% (119 of 189)
Number of Equal Sum Khipus with Verso Cords: 55% (104 of 189)
Number of Equal Sum Khipus with Mixed Cord Attachments: 40% (75 of 189)
Number of Equal Sum Khipus with Unknown Cord Attachments: 22% (41 of 189)
Here we see a significant increase (from 26% to 40%) of mixed attachment khipus when we move from the general base of all khipus to khipus with Equal Sums. This is added evidence that Equal Sums are allied with moiety information and/or ayni/reciprocity.
3.9 MultiSummands
We know from the fieldmark sorting above that MultiSummands most closely associate with the Equal Sum fieldmarks. What else can we learn? How closely do various measures associate?
Code
pps_sums_dict = {aKhipu.kfg_name(): pps_fieldmark.num_sums(aKhipu.kfg_name()) for aKhipu in all_khipus}pps_equal_sum_dict = {aKhipu.kfg_name(): pps_fieldmark.num_equal_sums(aKhipu.kfg_name()) for aKhipu in all_khipus}pps_multisummand_dict = {aKhipu.kfg_name(): pps_fieldmark.num_multisummands(aKhipu.kfg_name()) for aKhipu in all_khipus}pps_path_length_dict = {aKhipu.kfg_name(): pps_fieldmark.maximum_sum_path(aKhipu.kfg_name())[0] for aKhipu in all_khipus}print(f"Degrees Between Fieldmarks: # pps_sums and # equal sums = {uloom.degrees_between_dicts(pps_equal_sum_dict, pps_sums_dict):.3}")print(f"Degrees Between Fieldmarks: # pps multisummands and # equal_sums = {uloom.degrees_between_dicts(pps_equal_sum_dict, pps_multisummand_dict):.3}")print(f"Degrees Between Fieldmarks: # pps multisummands and # pps_sums = {uloom.degrees_between_dicts(pps_sums_dict, pps_multisummand_dict):.3}")print(f"Degrees Between Fieldmarks: # pps multisummands and pps_max_path_length = {uloom.degrees_between_dicts(pps_path_length_dict, pps_multisummand_dict):.3}")
Degrees Between Fieldmarks: # pps_sums and # equal sums = 20.5
Degrees Between Fieldmarks: # pps multisummands and # equal_sums = 30.3
Degrees Between Fieldmarks: # pps multisummands and # pps_sums = 33.8
Degrees Between Fieldmarks: # pps multisummands and pps_max_path_length = 58.6
Well thatâs not a useful approach.
4. Equal Sum Network Topology: Waterfall vs Pyramid vsâŠ
We can generate quick heuristics to search for Pyramid versus WaterfallEqual Sum topologies.
In his statistical review, AgustĂn Da Fieno Delucchi demonstrates a more generalized approach with more topologies.
4.1 Searching for Equal Sum Pyramid Topology Khipus
Code
plot_title ="Max Sum Path Length vs. Normalized Location-Max Equal Sum Cord / Size=# Equal Sums - Hover for info"fig = (px.scatter(pps_khipu_equal_sum_cord_stats_df, x="max_sum_path_length", y="normalized_max_cord_location", size="num_equal_sums", color="max_cord_value", labels={"kfg_name": "KFG Name", "num_pendant_cords": "# Pendant Cords","num_equal_sums": "# Equal Sums", "normalized_max_cord_location": "Normalized Location of Max Equal Sum Cord","max_sum_path_length": "Max Sum Path Length","mean_cord_value": "Mean Cord Value", "max_cord_value": "Max Cord Value", "mean_num_summands": "Mean # Summands per Equal Sum", "final_ordinal": "Final Ordinal in Sum Path", "max_cord_value": "Max Cord Value", "longest_path": "Longest Path"}, hover_name='kfg_name', hover_data=['num_pendant_cords', 'num_equal_sums', 'final_ordinal', 'max_cord_value', 'max_sum_path_length', 'longest_path'], title=plot_title, width=944, height=944) .update_layout(showlegend=True, yaxis_title="Normalized Location of Max Equal Sum Cord", xaxis_title="Max Khipu Sum Path Length", font=dict(family="ETBookOT")) .update(layout_coloraxis_showscale=True).show() )
Hovering over the circles in the above graphic, four khipus with a high number of Equal Sums stand out as possible example âpyramidâ khipus:
plot_title ="Max Sum Path Length vs. Last Ordinal in Longest Path (Size=# Equal Sums) - Hover for info"fig = (px.scatter(pps_khipu_equal_sum_cord_stats_df, x="max_sum_path_length", y="normalized_final_ordinal", log_y=True, size="num_pendant_cords", color="max_cord_value", labels={"kfg_name": "KFG Name", "num_pendant_cords": "# Pendant Cords","num_equal_sums": "# Equal Sums", "mean_cord_value": "Mean Cord Value", "max_cord_value": "Max Cord Value", "mean_num_summands": "Mean # Summands per Equal Sum", "normalized_final_ordinal": "Normalized Final Ordinal in Sum Path", "max_sum_path_length": "Max Sum Path Length","longest_path": "Longest Path" }, hover_name='kfg_name', hover_data=['num_pendant_cords', 'num_equal_sums', 'normalized_final_ordinal', 'max_cord_value', 'max_sum_path_length', 'longest_path'], title=plot_title, width=944, height=944) .update_layout(showlegend=True, yaxis_title="Normalized Ordinal Location of Final Cord in Longest Path (Log Scale)", xaxis_title="Max Khipu Sum Path Length", font=dict(family="ETBookOT")) .update(layout_coloraxis_showscale=True).show() )
Hovering over the circles in the above graphic, four khipus at the bottom stand out as possible sample âwaterfallâ khipus. Similarly hovering over the sum path length of 4 identifies two âpyramid khipusâ - KH0232, our case study, and KH0252
4.3 A Generalization of Equal Sum Topology and Statistical Review
In AgustĂn Da Fieno Delucchiâs independant statistical review he creates a network graph topology that includes all three sum relationships pendant-pendant, pendant-index, and pendant-color. From that he generalizes to the following topologies:
Type
Example
Number of Khipus
Waterfall
152
Pyramid
162
Cascade
147
Distributed
79
His interpretation of his data:
Multi-label is the norm. The most common single combination carries all five labels (50 components). Multi-root alone accounts for 93 % of components (183/196), confirming that the typical Equal Sum structure contains multiple top-level accounting entries whose underlying summand cords overlap â i.e., the weakly-connected component in the cord graph spans several simultaneous summation hierarchies rather than a single root.
Primary positional patterns. Pyramid (165) and Waterfall (153) are the most common positional labels. They co-occur in 133 of 165 Pyramid components (81 %), showing that a khipu which organizes Equal Sums around its midpoint almost always also opens with a directed grand-total chain. The two canonical archetypes are not alternatives â they are facets of the same structure.
Cascade (145, 74 %) co-occurs tightly with Waterfall (124/153 = 81 %). Deep chains (depth â„ 3) almost always originate early in the khipu. This confirms that hierarchical depth is a feature of the Waterfall pattern, not an independent mode.
Distributed (79, 40 %). Four in ten components have Equal Sum cords spread across more than 40 % of the khipuâs physical length. Combined with the Multi-root finding, this suggests a âledgerâ mode of organisation where accounting entries are distributed throughout the cord run rather than clustered at a single location.
Salience Ordering(./equal_sums_inquiry_stats.html#a-scribal-methodology-salience-ordering). Summand cord values decrease as they become farther from the sum cord. >The gradient suggests a deliberate recording convention: enter the most significant item first (adjacent to â), then proceed outward in descending order of magnitude. This is a form of salience ordering â structuring a list by importance rather than, say, arrival sequence or physical position. Equal Sum topologies provide an additional type of fieldmark to khipus just like cord color, or cord attachment.
5. Conclusions
This study has shown that Equal Sums:
Can serve as a Direct Assertion of equality, i.e., a simple balancing of sums; mathematically âA = âB . For example, we might want to ensure that the Hanan and Hurin moieties end up contributing equally. The pronounced association of Equal Sums with Recto/Verso symmetry suggests that this was a common case.
They can also serve as an Indirect Assertion of equality. In the above Case 1 study we saw an equal cord asserting a considerably more advanced mathematical equation: \(L_{:51} + L_{k:6} + C_{:68} + R_{k:7} + R_{:17} = C_{:68} + (L_{k:6} + C_{:68} + R_{k:7})\)
Since multiterm, nested equations exist, and can be identified, we now have the ability to manipulate the equations. We can now use substitution, rearrangement, cancellation, etc of terms in a khipuâs equations to understand the underlying structure of the khipu.
As an example, this ability allows us to search for, and find, khipus with double-entry accounting patterns, such as KH0696. Additionally, accounting practices such as crosstabs, are now visible.
Since we now have equations of equality, we can chain those equations together to form more complex equations. For example, Equal Sums can be chained together to form a structured topology, such as a Waterfall or Pyramid, or Cascade.
Similar to other khipus signs such as seriation or banding, recto vs verso, etc. these topologies provide an additional type of sign characterization to khipus in the field.
Finally, and perhaps the most importantly, we now have insights and techniques to allow us to map regions of a khipu by function. This section Adds these two sections, this section is a set of Crosstabs, etc.
To Karen Thompson, without whom we would not have the wonderful Khipu Field Guide khipu database foundation we have now.
To Mackinley FitzPatrick, whose suggestion, that we use a Case Study approach, resulted in revealing the equational structures.
To Manuel Medrano, for framing our insights as a larger discussion about khipu algebra.
To Kylie Quave, for teaching us her insightful guidelines about writing, community, and joy.
7. Bibliography
Ascher, Marcia, and Robert Ascher. 1978. Code of the Quipu Databook. Ann Arbor, MI: University of Michigan Press.
Ascher, Marcia, and Robert Ascher. 1988. Code of the Quipu Databook II. Ithaca, NY: Ascher and Ascher.
Buckmaster, Dale. 1974. âThe Incan Quipu and the Jacobsen Hypothesis.â Journal of Accounting Research 12 (1): 178â181.
Clindaniel, Jon. 2019. Toward a Grammar of the Inka Khipu: Investigating the Production of Non-numerical Signs. PhD dissertation, Department of Anthropology, Harvard University.
Forrester, D. A. R. 1968. âThe Incan Contribution to Double-Entry Accounting.â Journal of Accounting Research 6 (2): 283.
Jacobsen, Lyle E. 1964. âThe Ancient Inca Empire of Peru and the Double Entry Accounting Concept.â Journal of Accounting Research 2 (2): 221â228.
Locke, L. Leland. 1923. The Ancient Quipu or Peruvian Knot Record. New York: American Museum of Natural History.
Khosla, Ashok. 2026. The Khipu Field Guide. https://www.khipufieldguide.com.
Medrano, Manuel, and Ashok Khosla. 2024. âHow Can Data Science Contribute to Understanding the Khipu Code?â Journal of Latin American Antiquities, May 2024.
Pizarro, Hernando. (1533) 1920. âA los señores oydores de la audiencia real de su magestad.â Informaciones sobre el antiguo PerĂș, edited by Horacio H. Urteaga, 16â180. Vol. 3. Lima: SanmartĂ.
Thompson, Karen M., 2024. A Numerical Connection Between Two Khipus. Ăawpa Pacha, pp.1-22.
Thompson, Karen M. Private communication, September 8, 2026.
Urton, Gary. 2005. âKhipu Archives: Duplicate Accounts and Identity Labels in the Inka Knotted String Records.â Latin American Antiquity 16 (2): 147â167.
Urton, Gary. 2009. âSin, Confession, and the Arts of Book- and Cord-Keeping: An Intercontinental and Transcultural Exploration of Accounting and Governmentality.â Comparative Studies in Society and History 51 (4): 801â831. https://doi.org/10.1017/S0010417509990144.
Urton, Gary, and Alejandro Chu. 2019. âThe Invention of Taxation in the Inka Empire.â Latin American Antiquity 30 (1): 1â16.
8. Appendix. An Introduction to Double Entry Accounting
8.1. The Development of Double Entry Accounting
Luca Pacioli, a Franciscan friar born around 1445 in Sansepolcro, Italy, is often called the âfather of accounting,â though he didnât actually invent double-entry bookkeeping. Italian merchants in Venice, Florence, and Genoa had been using versions of the system for roughly two centuries before he wrote about it. The earliest known example dates to a merchantâs ledger from 1299â1300. What Pacioli did was something different but equally important: in 1494 he published a massive 615-page math textbook, Summa de Arithmetica, which included a 27-page section describing this bookkeeping method in clear, systematic terms. He also chose to write in everyday Italian rather than scholarly Latin, and thanks to the recently invented printing press, his book spread across Europe far faster than any handwritten manual could have. In effect, he took a widespread but informally taught merchant practice and turned it into the first accessible instruction manual.
Double Entry Accounting is built on the fundamental equation of:
Assets = Equities + Liabilities
The system itself, what Pacioli called âthe Method of Veniceâ, is built on one simple idea: every transaction has two sides, and they must always balance. If a business sells goods for cash, two things happen at once: cash goes up and revenue goes up. If a company borrows money, cash goes up and so does debt. Pacioli described three connected records for tracking this: the memoriale (a rough daily log of transactions), the giornale (a more formal journal), and the quaderno (the ledger, where entries were sorted into individual accounts). At the end of the process, a trial balance checked that total debits equaled total credits, and if they didnât, that mismatch flagged an error or possible fraud. This was a major upgrade from the single-entry lists many merchants had used before, which made it nearly impossible to catch mistakes or get a true picture of a businessâs finances.
The impact of this system went well beyond bookkeeping. Because records were now standardized and self-checking, business partners and investors could verify a companyâs finances without having to simply trust the ownerâs word, which made it easier for strangers to do business together and for companies to grow larger and more complex. Historians see this as one of the building blocks that helped modern capitalism expand. Pacioliâs personal life adds an interesting footnote to the story too: while working in Milan, he became close friends with Leonardo da Vinci, tutoring him in geometry while Leonardo illustrated Pacioliâs later book on the golden ratio, De Divina Proportione (1509); the only book Leonardo illustrated in his lifetime. More than 500 years later, the core logic Pacioli documented, balanced, double-sided entries, still underlies virtually every accounting system in use today, from simple spreadsheets to enterprise software.
8.2 How Double-Entry Accounting Works â An Example:
When you sell a computer in double-entry accounting, you would typically make entries to reflect the transaction in both the asset and equity sides of the accounting equation. Letâs break down the entry:
Identify the accounts involved:
You would credit (decrease) an asset account, such as âInventoryâ (if youâre selling from your inventory).
You would debit (increase) an asset account, such as âCashâ or âAccounts Receivableâ (if the customer pays immediately or on credit).
You would credit (increase) an income account, such as âSales Revenueâ or âSales Income,â to recognize the revenue from the sale.
Determine the amounts:
Debit the âInventoryâ account for the cost of the computer that you sold.
Credit the âCashâ account if the customer paid immediately or âAccounts Receivableâ if they will pay later.
Credit the âSales Revenueâ account for the selling price of the computer.
Hereâs how you would list the entry:
Account
Debit (+)
Credit (-)
Inventory
Cost of computer
Cash or Accounts Receivable
Selling price of computer
Sales Revenue
Selling price of computer
For example, if you sold a computer for $1,000 that originally cost you $800, and the customer paid in cash:
Account
Debit (+)
Credit (-)
Inventory
$800
Cash
$1,000
Sales Revenue
$1,000
This entry reflects the decrease in inventory (debit), increase in cash (credit), and recognition of sales revenue (credit) from the computer sale.