public class Pullback // maybe Pushout { private Category category_; private IniSettings ini; private int obj; private int alpha[]; private int beta[]; private int numpullbacks; private String output; private String type; private boolean supress_output; private boolean endopassed; public static final int ERROR = -1; public static final int PULLBACK = -5; public static final int NOT_PULLBACK = -6; public Pullback(Category category, String type_) { category_ = category; ini = category_.ini; output = ""; type = type_; // one of "pullback" or "pushout" numpullbacks = 0; supress_output = false; endopassed = false; alpha = new int [ini.getMAXWORD()]; beta = new int [ini.getMAXWORD()]; } public boolean isPullback(int pullbackobj, int alpha[], int beta[], int lambda[], int rho[], int maxloop) /* Parameters: pullbackobj: the object of the pullback being tested lambda: first projection of the pullback rho: second projection of the pullback alpha: beta: Local Variables: pullbackobj: is currently being tested for pullback property path: keeps track of the current path from testobj to pullbackobj objects: array of integers storing the number of times each object has been visited in current path id: a path that has a value of -2 and represents the identity arrow homTP: tree of all arrows to pullbackobj from testobj imageHomTP: tree of gamma lambdas with gamma rho subtrees homTB: tree of all arrows to domain of rho from testobj p, tp: temporary pointers reduced_lambda, reduced_rho : normalized versions of the projections Purpose: -- This function checks for pullback(s) of a cospan alpha:A-->C<--B:beta. -- The pullback object is P and projections are lambda:A<--P-->B:rho. -- A test object T and test arrows are delta:A<--T-->B:epsilon. -- P is a pullback if alpha*lambda = beta*rho, and, for every T, if there is a pair such that alpha*delta = beta*epsilon, there exists a unique gamma:T-->P, such that lambda*gamma = delta and rho*gamma = epsilon. To check each object in the category for 1-1 and onto. Design: Returns true if object is a pullback, and false if not. */ { int path[] = new int[ini.getMAXWORD()]; // the current path int id[] = new int[2]; // an identity arrow int reducedLambda[] = new int[ini.getMAXWORD()]; // lambda: P-->A int reducedRho[] = new int[ini.getMAXWORD()]; // rho: P-->B HomTree imageHomTP; // all paths from T-->P (gammas) composed with lambdas and rhos HomTree homTP; //all paths from T-->P (gammas) HomTree homTB; //all paths from T-->B (will be bigger than imageHomTP) HomTree pathtree; // just stores paths i think int obj, i, codom; // obj is test object, codom is current domain // test each object in the category for (obj=0; objA num_arrs_homPA++; // increment the number of paths from P-->A } if (category_.object_number(rhoObject) == obj) { homPB.addPath(path); // add the identity to the paths from P-->B num_arrs_homPB++; // increment the number of paths from P-->B } if (category_.object_number(lambdaObject) == category_.object_number(otherObject)) { homAC.addPath(path); // add the identity to the paths from A-->C num_arrs_homAC++; // increment the number of paths from A-->C } if (category_.object_number(rhoObject) == category_.object_number(otherObject)) { homBC.addPath(path); // add the identity to the paths from B-->C num_arrs_homBC++; // increment the number of paths from B-->C } // we don't want the isPullback function telling the user which objects // aren't sums, so we supress that output supress_output = true; // now loop through each combination of four of arrows to the first object from the pullback object // lambda, rho, beta, and alpha will store the temporary paths; each one will start at // as the first path in the appropriate homtree; lambda = homPA, rho = homPB, alpha = homAC, // beta = homBC; lambda = homPA.getFirstPath(); for (int i=0; i we have P, alpha, and beta. ---> we need to generate lambda and rho, then: ---> check conditions; alpha and beta must have the same codomain; compose alpha and lambda, beta and rho, reduce and then check for equality (i.e. alpha*lambda = beta*rho). ---> now use isPullback function to check whether P is a pullback.*/ int pullbackobj; // "P"...the object to be tested for the pullback property HomTree homPA = new HomTree(); HomTree homPB = new HomTree(); HomTree pathtree = new HomTree(); // stores paths i think...not very useful int path[] = new int[ini.getMAXARR()]; int lambda[]; // the lambda path (P-->A) int rho[]; // the rho path (P-->B) if (!category_.check_obj(objchr)) // check to see if the object is in the category { output += objchr + " is not an object of " + category_.name + "."; return ERROR; } else { pullbackobj = category_.object_number(objchr); // set the pullback object to be the String // check to see that all the arrows in the paths are valid (not checking domain/codomain matching) if (category_.check_string(alphaF) && category_.check_string(betaF)) { alpha = category_.string_to_path(alphaF); // convert the strings to paths beta = category_.copy_path(category_.string_to_path(betaF)); // check to see that all the paths are valid in the category (match domain and codomains) if (category_.check_path(alpha) && category_.check_path(beta)) { alpha = category_.reduce(alpha); // reduce all the paths beta = category_.reduce(beta); // check to see that alpha and beta have the same codomain; if (alpha[0] >= 0 && beta[0] >= 0 && category_.arr[alpha[0]][1] != category_.arr[beta[0]][1]) { if (type.equalsIgnoreCase("pullback")) output+="Alpha and beta paths must have same codomain."; else if (type.equalsIgnoreCase("pushout")) output+="Alpha and beta paths must have same domain."; return ERROR; } // check to see that lambda and rho have the same domain else { path[0] = -1; // reset the path int num_arrs_homPA = makeHomTree(path, homPA, pullbackobj, category_.arr[alpha[category_.path_len(alpha)-1]][0], ini.getMaxLoop(), pathtree); pathtree = new HomTree(); // reset the pathtree path[0] = -1; // reset the path int num_arrs_homPB = makeHomTree(path, homPB, pullbackobj, category_.arr[beta[category_.path_len(beta)-1]][0], ini.getMaxLoop(), pathtree); pathtree = new HomTree(); // reset the pathtree path[0] = -2; path[1] = -1; // reset the path lambda = homPA.getFirstPath(); supress_output = true; for (int i=0; i we have P, alpha, beta, lamba, and rho. ---> check conditions; alpha and beta must have the same codomain; compose alpha and lambda, beta and rho, reduce and then check for equality (i.e. alpha*lambda = beta*rho). ---> now use isPullback function to check whether P is a pullback.*/ int pullbackobj; // "P"...the object to be tested for the pullback property HomTree pathtree = new HomTree(); // stores paths i think...not very useful int lambda[]; // the lambda path (P-->A) int rho[]; // the rho path (P-->B) if (!category_.check_obj(objchr)) // check to see if the object is in the category { output += objchr + " is not an object of " + category_.name + "."; return ERROR; } else { pullbackobj = category_.object_number(objchr); // set the pullback object to be the String // check to see that all the arrows in the paths are valid (not checking domain/codomain matching) if (category_.check_string(alphaF) && category_.check_string(betaF) && category_.check_string(lambdaF) && category_.check_string(rhoF)) { alpha = category_.string_to_path(alphaF); // convert the strings to paths beta = category_.copy_path(category_.string_to_path(betaF)); lambda = category_.string_to_path(lambdaF); rho = category_.string_to_path(rhoF); // check to see that all the paths are valid in the category (match domain and codomains) if (category_.check_path(alpha) && category_.check_path(beta) && category_.check_path(lambda) && category_.check_path(rho)) { alpha = category_.reduce(alpha); // reduce all the paths beta = category_.reduce(beta); lambda = category_.reduce(lambda); rho = category_.reduce(rho); // check to see that alpha and beta have the same codomain; if (alpha[0] >= 0 && beta[0] >= 0 && category_.arr[alpha[0]][1] != category_.arr[beta[0]][1]) { if (type.equalsIgnoreCase("pullback")) output+="Alpha and beta paths must have same codomain."; else if (type.equalsIgnoreCase("pushout")) output+="Alpha and beta paths must have same domain."; return ERROR; } // check to see that lambda and rho have the same domain else if (lambda[0] >= 0 && rho[0] >= 0 && category_.arr[lambda[category_.path_len(lambda)-1]][0] != category_.arr[rho[category_.path_len(rho)-1]][0]) { if (type.equalsIgnoreCase("pullback")) output+="Lambda and rho paths must have same domain."; else if (type.equalsIgnoreCase("pushout")) output+="Lambda and rho paths must have same codomain."; return ERROR; } // check to see that the domain of lambda and rho is the pullback object else if (lambda[0] >= 0 && rho[0] >= 0 && category_.arr[lambda[category_.path_len(lambda)-1]][0] != pullbackobj) { if (type.equalsIgnoreCase("pullback")) output+="Domain of lambda and rho must be the pullback object."; else if (type.equalsIgnoreCase("pushout")) output+="Codomain of lambda and rho must be the pushout object."; return ERROR; } else { // check to see that the square commutes (alpha*lambda = beta*rho) if (category_.equals(category_.reduce(category_.append_path(lambda, alpha)), category_.reduce(category_.append_path(rho, beta)))) { // then check for the pullback property if (isPullback(pullbackobj, alpha, beta, lambda, rho, ini.getMaxLoop())) { output+=category_.obj[pullbackobj] + " is a " + type + " of " + alphaF + " and " + betaF + " with projections " + lambdaF + " and " + rhoF + "."; return PULLBACK; } else { output+=category_.obj[pullbackobj] + " is not a " + type + " of " + alphaF + " and " + betaF + "."; return NOT_PULLBACK; } } else { if (type.equalsIgnoreCase("pullback")) output+="alpha*lambda must equal beta*rho."; else if (type.equalsIgnoreCase("pushout")) output+="lambda*alpha must equal rho*beta."; return ERROR; } } } else // if at least one of the paths isn't valid, return ERROR and appropriate output { if (!category_.check_path(alpha)) output+="Invalid alpha path.\n"; if (!category_.check_path(beta)) output+="Invalid beta path.\n"; if (!category_.check_path(lambda)) output+="Invalid lambda path.\n"; if (!category_.check_path(rho)) output+="Invalid rho path.\n"; return ERROR; } } else // if at least one of the paths doesn't contain proper arrows, return ERROR and appropriate output { if (!category_.check_string(alphaF)) output+="Invalid alpha path.\n"; if (!category_.check_string(betaF)) output+="Invalid beta path.\n"; if (!category_.check_string(lambdaF)) output+="Invalid lambda path.\n"; if (!category_.check_string(rhoF)) output+="Invalid rho path.\n"; return ERROR; } } } public boolean check_oneone(int gamma[], int domain, int codomain, HomTree imageHomTP, int lambda[], int rho[], HomTree homTP, int maxloop, HomTree pathtree) /* Parameters: gamma: the current path (trying to go from T-->P) domain: the current object of the path codomain: the object we are trying to find all arrows to (P, the pullback object) objects: an array of integers which keeps the function from exceeding the maximum number of loops imageHomTP: a tree returned with all gamma-lambdas and gamma-rhos lambda: first projection from the pullbackobj being tested rho: second projection from the pullbackobj being tested homTP: the tree of all arrows to pullbackobj from domain maxloop : endomorphism limit Purpose: To generate the reduced hom set from T to P and check that the pullback object (P) is one-to-one (injective); if lambda*gamma = lambda*gamma' and rho*gamma = rho*gamma', where gamma!=gamma', then it is not one-to-one (injective) Design: Creates a tree imageHomTP containing the reduced form of all the gamma-lambdas and each gamma-lambda having a subtree which contains all of the gamma-rhos paired with it. Also creates a tree homTP with all the gamma paths */ { int i, j = 0; // i and j are used in for...loops int len = 0; // length of the gamma path int number = 0; // the number of arrows from the current domain int codom, endo = 0; // codom is the current codomain of gamma int arrow_array[] = new int[category_.num_arrows]; // stores all of the arrows from the current domain int reducedGammaLambda[] = new int[category_.ini.getMAXWORD()]; // the reduced composition lambda*gamma int reducedGammaRho[] = new int[category_.ini.getMAXWORD()]; // the reduced composition beta*gamma gamma = category_.reduce(gamma); // make sure the current path (gamma) is reduced len = category_.path_len(gamma); // store the length of gamma in 'len' if (gamma[0] == -2) // if gamma is the identity arrow gamma[0] = -1; // set it to be an empty path /* check all of the arrows in the gamma path; if any of the codomains of * the arrows are equal to the domain of the first arrow (i.e. the start of the path), * increment endo; if the starting domain is found on too many of the arrows, * we will not perform the algorithm */ for (i=0; i=0; j--) gamma[j+1] = gamma[j]; // add the ith arrow to the path gamma[0] = arrow_array[i]; // then check all arrows from the object recursively. if (!check_oneone(gamma, domain, codomain, imageHomTP, lambda, rho, homTP, maxloop, pathtree)) return false; // if one of these checks returns false, the entire thing is false (i.e. not one-to-one) len = category_.path_len(gamma); // store the new length of the current path (gamma) for (j=0; jA) alpha: the path from A-->C; must equal beta*epsilon when composed with delta beta: the path from B-->C; must equal alpha*delta when composed with epsilon domain: the current object of the path (starts out as T) codomain:the object we are trying to find all arrows to (A) maxloop: an integer that keeps the function from exceeding the maximum number of loops imageHomTP: the tree of lambda*gammas with rho*gammas homTB: a tree of all the rhos (paths from T-->B) Local Variables: number: stores the number of arrows from an object current_arrow: stores the number of the current arrow in the path codom: stores the codomain of the current arrow arrow_array: contains all of the arrows from the last object on the path Purpose: To check that a pullback is onto; i.e. for every delta such that alpha*delta = beta*epsilon, the pair is already in imageHomTP. Design: Generates all of the deltas from one object to another and uses homTB tree it is passed to check that all of the pairs are in imageHomTP. */ { int i, j = 0; // i and j are used in for...loops int len = 0; // length of the gamma path int number = 0; // the number of arrows from the current domain int codom, endo = 0; // codom is the current codomain of gamma; endo is the number of times the domain object occurs in the path int arrow_array[] = new int[category_.num_arrows]; // stores all of the arrows from the current domain delta = category_.reduce(delta); // make sure the current path (gamma) is reduced if (delta[0] == -2) // if delta is the identity arrow delta[0] = -1; // set it to be an empty path len = category_.path_len(delta); /* check all of the arrows in the delta path; if any of the codomains of * the arrows are equal to the domain of the first arrow (i.e. the start of the path), * increment endo; if the starting domain is found on too many of the arrows, * we will not perform the algorithm */ for (i=0; i is in imageHomTP int epsilon[] = new int[1]; // construct epsilon path epsilon = homTB.getFirstPath(); // set epsilon path to be the first path in the homTB tree for (j=0; j); return false } } } epsilon = homTB.getNextPath(); // check the next epsilon in the homTB tree } } if (delta[0] == -2) delta[0] = -1; // if delta is an identity arrow, set it to be an empty path number = category_.all_arr(domain, arrow_array); // store all arrows from the current domain in arrow_array if (number > 0) for (i=0; i=0; j--) delta[j+1] = delta[j]; // add the new arrow to the path delta[0] = arrow_array[i]; // recursively check all paths; like a depth-first search if (!check_onto(delta, alpha, beta, domain, codomain, imageHomTP, homTB, maxloop, pathtree)) return false; // if any of the checks return false, it is not onto for (j=0; j<=len; j++) delta[j] = delta[j+1]; // remove the newest arrow from the path; "pop" it } } } else { endopassed = true; // set endopassed to be true, and return false; not sure why...check_oneone doesn't return false in this case return false; } return true; } public int makeHomTree(int path[], HomTree homtree, int obj1, int obj2, int maxloop, HomTree pathtree) /* Parameters: path[] - integer array containing the path followed so far objects[] - integer array containing a list of all the objects visited along the path homtree - the tree to contain the paths obj1 and obj2 - check for paths from obj1 to obj2 maxloop - max endomorphism limit Purpose: To generate the reduced hom set from one object to another as a tree Design: Creates a tree homtree of all the reduced paths from one object to another. */ { int i, j; // i and j are used in for...loops int endo = 0; // endo is the number of times the domain object occurs in the path path = category_.reduce(path); // reduce the path int pathlen = category_.path_len(path); // store the length of the path in 'pathlen' int numpaths = 0; // store the total number of paths if (path[0] == -2) // if the path is an identity arrow, set it to be an empty path path[0] = -1; /* check all of the arrows in the current path; if any of the codomains of * the arrows are equal to the domain of the first arrow (i.e. the start of the path), * increment endo; if the starting domain is found on too many of the arrows, * we will not perform the algorithm */ for (i=0; i=0; i--) // all arrows from obj1 { // add the new arrow to the path, and the new object to the object list for (j=category_.path_len(path); j>=0; j--) path[j+1] = path[j]; path[0] = arrows[i]; // recursive check on all paths; like a depth-first search on a graph numpaths += makeHomTree(path, homtree, category_.arr[arrows[i]][1], obj2, maxloop, pathtree); // now remove the arrow and object from the path and object list for (j=0; j<=pathlen; j++) path[j] = path[j+1]; } // if we're at the second object, then add the path to the tree if (obj1 == obj2 && pathlen != 0) { numpaths++; homtree.addPath(newpath); // add the path to the homtree } } } else { endopassed = true; } return numpaths; } public int getNumPullbacks() { return numpullbacks; } public void setNumPullbacks(int newNumPullbacks) { numpullbacks = newNumPullbacks; } public String getOutput() { return output; } public void setOutput(String newOutput) { output = newOutput; } public boolean getSupressOutput() { return supress_output; } public void setSupressOutput(boolean newSupressOutput) { supress_output = newSupressOutput; } public boolean getEndoPassed() { return endopassed; } public void setEndoPassed(boolean newEndoPassed) { endopassed = newEndoPassed; } }