def validateCoherence(arySegments): # Collapse all segments into a single list and measure coherence aryVectors = [ i for f, ary in arySegments for i in ary ] aryCoherence = [ 0 for i in xrange(len(aryVectors)) ] for i in xrange(2, len(aryVectors)): if Codons.isCoherent([ aryVectors[i-2], aryVectors[i-1], aryVectors[i-0] ]): aryCoherence[i-2] += 1 aryCoherence[i-1] += 1 aryCoherence[i-0] += 1 # Divide measured coherence into lists matching the original segments for i in xrange(len(arySegments)): aryCoherence[i:i] = [ aryCoherence[i:i+len(arySegments[i][1]) ] ] aryCoherence[i+1:i+1+len(arySegments[i][1])] = [] # Check the expected coherence of each segment against that measured for i in xrange(len(arySegments)): fCoherent, aryVectors = arySegments[i] if (fCoherent and aryCoherence[i].count(0)) or (not fCoherent and (aryCoherence[i].count(0) != len(aryCoherence[i]))): if i > 0: fC, aryV = arySegments[i-1] Common.sayError('Coherent(%c) %d - %s' % (fC and 'T' or 'F', len(aryV), ' '.join([ Codons.Vectors.toName(id) for id in aryV ]))) Common.sayError('Coherent(%c) %d - %s' % (fCoherent and 'T' or 'F', len(aryVectors), ' '.join([ Codons.Vectors.toName(id) for id in aryVectors ]))) Common.sayError(' - %s' % ' '.join([ ' %d ' % j for j in aryCoherence[i] ])) if i < len(arySegments)-1: fC, aryV = arySegments[i+1] Common.sayError('Coherent(%c) %d - %s' % (fC and 'T' or 'F', len(aryV), ' '.join([ Codons.Vectors.toName(id) for id in aryV ]))) raise Common.BiologicError('Failed to create a gene with proper coherence - segment %d should be %s but has %s vectors' % (i+1, fCoherent and 'Coherent' or 'Incoherent', fCoherent and 'Incoherent' or 'Coherent'))
def buildGenes(uchHan, aryGenes): Common.say('Creating %d gene(s)' % len(aryGenes)) han = loadHan(uchHan) strAuthor = Globals.strAuthor and (" author='%s'" % Globals.strAuthor) or '' aryGeneNames = [] for specification in aryGenes: Common.say('Creating gene from specification ' + specification) gs = GeneSpecification(specification != Constants.strDefault and specification or '', han) gsName = gs.toName(han.unicode) + Common.Constants.extGene gsPoints = gs.getPoints() Common.say('Gene to be named ' + gsName) ptCurrent = Genome.Point(pt=gsPoints[0][1][0]) arySegments = [] # Convert each set of points into a list of vectors for iSegment in xrange(len(gsPoints)): fCoherent, aryPoints = gsPoints[iSegment] # Build the segment starting from the current location # - Ensure incoherent segments always begin at the current location # (This causes moves to absorb the tracing error, effectively trading placement error for stroke fit error.) if not fCoherent: aryPoints[0].x = ptCurrent.x aryPoints[0].y = ptCurrent.y ptCurrent, aryVectors = buildSegment(ptCurrent, fCoherent, aryPoints) if not fCoherent: # If the segment contains too few vectors, pad it with an incoherent sequence # - If there are no vectors, use No/So/Ea/We - binding code will ensure proper coherence at the endpoints # - Otherwise, use the four points of the direction "compass" that are guaranteed incoherent with the last vector if len(aryVectors) < 3: iDirection = len(aryVectors) and Codons.Directions.add(Codons.Vectors.toDirection(aryVectors[-1]), 3) or Codons.Directions.North aryVectors.append(Codons.Vectors.create(iDirection)) aryVectors.append(Codons.Vectors.create(Codons.Directions.toOpposite(iDirection))) iDirection = Codons.Directions.add(iDirection, 2) aryVectors.append(Codons.Vectors.create(iDirection)) aryVectors.append(Codons.Vectors.create(Codons.Directions.toOpposite(iDirection))) # Inject vectors to force incoherency for incoherent segments # - Essentially, add a vector pair to every two that forces incoherency # - Walking the list must take into account injected vector pairs else: iVector = 0 while iVector < len(aryVectors): if Codons.isCoherent([aryVectors[iVector-2], aryVectors[iVector-1], aryVectors[iVector+0]]): idVector = aryVectors[iVector] aryVectors.insert(iVector+0, Codons.Vectors.toOpposite(idVector)) aryVectors.insert(iVector+1, idVector) iVector += 1 # Ensure the vectors "bind" without affecting the coherence of an adjoining segment if iSegment: fCoherencePrev, aryVectorsPrev = arySegments[-1] if Codons.isCoherent([ aryVectorsPrev[-2], aryVectorsPrev[-1], aryVectors[0] ]) or Codons.isCoherent([ aryVectorsPrev[-1], aryVectors[0], aryVectors[1] ]): if not fCoherencePrev: aryVectorsPrev += [ Codons.Vectors.toOpposite(aryVectorsPrev[-1]), aryVectorsPrev[-1], aryVectors[0], Codons.Vectors.toOpposite(aryVectors[0]) ] else: aryVectors[:0] = [ Codons.Vectors.toOpposite(aryVectorsPrev[-1]), aryVectorsPrev[-1], aryVectors[0], Codons.Vectors.toOpposite(aryVectors[0]) ] arySegments.append((fCoherent, aryVectors)) validateCoherence(arySegments) aryCodons = [ Codons.Vectors.toVector(idVector).codon for fCoherent, aryVectors in arySegments for idVector in aryVectors ] aryCodons[:0] = [ 'ATG' ] aryCodons.append(Codons.Vectors.toVector(Codons.Vectors.create(Codons.Directions.Stop, Codons.Constants.iVectorShort)).codon) aryStrokes = [] iStroke = 0 iBase = 4 for fCoherent, aryVectors in arySegments: if fCoherent: aryStrokes.append(_GENE_STROKE % (iBase, iBase+(len(aryVectors)*3-1), gs.mapStrokeToHan(iStroke)+1)) iStroke += 1 iBase += len(aryVectors) * 3 strGene = _GENE_DEFINITION % (str(uuid.uuid4()).upper(), strAuthor, datetime.datetime.utcnow().isoformat(), _NAME, str(gs), ''.join(aryCodons), len(aryCodons)*3, gsPoints[0][1][0].x, gsPoints[0][1][0].y, han.unicode, '\n'.join(aryStrokes)) strPath = Common.resolvePath(os.path.join(Globals.strGenePath, Common.makeHanPath(gsName))) strDir = os.path.dirname(strPath) if not os.path.exists(strDir): try: os.makedirs(os.path.dirname(strPath)) except OSError, err: raise Common.BiologicError('Unable to create %s - %s' % (strDir, str(err))) try: fileGene = os.open(strPath, os.O_CREAT | os.O_TRUNC | os.O_WRONLY, 0664) os.write(fileGene, strGene) except IOError, err: raise Common.BiologicError('Unable to create %s - %s' % (strPath, str(err))) os.close(fileGene) Common.say('\tWrote %s - %d codons, %d bases' % (strPath, len(aryCodons), len(aryCodons)*3)) aryGeneNames.append(gsName) return aryGeneNames