func FixCds(sqlitePath string, sequence string, codontable CodonTable, problematicSequenceFuncs []func(string, chan DnaSuggestion, *sync.WaitGroup)) (string, error) {
	var db *sqlx.DB
	db = sqlx.MustConnect("sqlite3", sqlitePath)
	createMemoryDbSql := `
	CREATE TABLE codon (
		codon TEXT PRIMARY KEY,
		aa TEXT
	);

	CREATE TABLE seq (
		pos INT PRIMARY KEY
	);

	CREATE TABLE history (
		pos INTEGER REFERENCES seq(pos),
		codon TEXT NOT NULL REFERENCES codon(codon),
		step INT
	);

	-- Weights are set on a per position basis for codon harmonization at a later point
	CREATE TABLE weights (
		pos INTEGER REFERENCES seq(pos),
		codon TEXT NOT NULL REFERENCES codon(codon),
		weight INTEGER
	);

	CREATE TABLE codonbias (
		fromcodon TEXT REFERENCES codon(codon),
		tocodon TEXT REFERENCES codon(codon),
		gcbias TEXT
	);

	CREATE TABLE suggestedfix (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		step INTEGER,
		start INTEGER REFERENCES seq(pos),
		end INTEGER REFERENCES seq(pos),
		gcbias TEXT,
		quantityfixes INTEGER,
		suggestiontype TEXT
	);
`
	db.MustExec(createMemoryDbSql)
	// Insert codons
	weightTable := make(map[string]int)
	codonInsert := `INSERT INTO codon(codon, aa) VALUES (?, ?)`
	for _, aminoAcid := range codontable.AminoAcids {
		for _, codon := range aminoAcid.Codons {
			db.MustExec(codonInsert, codon.Triplet, aminoAcid.Letter)
			weightTable[codon.Triplet] = codon.Weight

			codonBias := strings.Count(codon.Triplet, "G") + strings.Count(codon.Triplet, "C")
			for _, toCodon := range aminoAcid.Codons {
				if codon.Triplet != toCodon.Triplet {
					toCodonBias := strings.Count(toCodon.Triplet, "G") + strings.Count(toCodon.Triplet, "C")
					switch {
					case codonBias == toCodonBias:
						db.MustExec(`INSERT INTO codonbias(fromcodon, tocodon, gcbias) VALUES (?, ?, ?)`, codon.Triplet, toCodon.Triplet, "NA")
					case codonBias > toCodonBias:
						db.MustExec(`INSERT INTO codonbias(fromcodon, tocodon, gcbias) VALUES (?, ?, ?)`, codon.Triplet, toCodon.Triplet, "AT")
					case codonBias < toCodonBias:
						db.MustExec(`INSERT INTO codonbias(fromcodon, tocodon, gcbias) VALUES (?, ?, ?)`, codon.Triplet, toCodon.Triplet, "GC")
					}
				}
			}
		}
	}

	// Insert seq and history
	pos := 0
	for i := 0; i < len(sequence)-3; i = i + 3 {
		codon := sequence[i : i+3]
		db.MustExec(`INSERT INTO seq(pos) VALUES (?)`, pos)
		db.MustExec(`INSERT INTO history(pos, codon, step) VALUES (?, ?, 0)`, pos, codon)
		db.MustExec(`INSERT INTO weights(pos, codon, weight) VALUES (?,?,?)`, pos, codon, weightTable[codon])
		pos++
	}

	var err error
	// For a maximum of 1000 iterations, see if we can do better
	for i := 1; i < 100; i++ {
		suggestions := findProblems(sequence, problematicSequenceFuncs)
		// If there are no suggestions, break the iteration!
		if len(suggestions) == 0 {
			break
		}
		for _, suggestion := range suggestions { // if you want to add overlaps, add suggestionIndex
			// First, let's insert the suggestions that we found using our problematicSequenceFuncs
			_, err = db.Exec(`INSERT INTO suggestedfix(step, start, end, gcbias, quantityfixes, suggestiontype) VALUES (?, ?, ?, ?, ?, ?)`, i, suggestion.Start, suggestion.End, suggestion.Bias, suggestion.QuantityFixes, suggestion.SuggestionType)
			if err != nil {
				return sequence, err
			}
		}

		// The following statements are the magic sauce that makes this all worthwhile.
		// Parameters: step, gcbias, start, end, quantityfix
		sqlFix1 := `INSERT INTO history
		            (codon,
		             pos,
		             step)
		SELECT t.codon,
		       t.pos,
		       ? AS step
		FROM   (SELECT cb.tocodon AS codon,
		               s.pos      AS pos
		        FROM   seq AS s
		               JOIN history AS h
		                 ON h.pos = s.pos
		               JOIN weights AS w
		                 ON w.pos = s.pos
		               JOIN codon AS c
		                 ON h.codon = c.codon
		               JOIN codonbias AS cb
		                 ON cb.fromcodon = c.codon
		        WHERE `
		sqlFix2 := ` s.pos >= ?
		               AND s.pos <= ?
		               AND h.codon != cb.tocodon
		        ORDER  BY w.weight) AS t
		GROUP  BY t.pos
		LIMIT  ?; `

		independentSuggestions := []DnaSuggestion{}
		db.Select(&independentSuggestions, `SELECT * FROM suggestedfix WHERE step = ?`, i)

		for _, independentSuggestion := range independentSuggestions {
			switch independentSuggestion.Bias {
			case "NA":
				db.MustExec(sqlFix1+sqlFix2, i, independentSuggestion.Start, independentSuggestion.End, independentSuggestion.QuantityFixes)
			case "GC":
				db.MustExec(sqlFix1+`cb.bias = 'GC' AND `+sqlFix2, i, independentSuggestion.Start, independentSuggestion.End, independentSuggestion.QuantityFixes)
			case "AT":
				db.MustExec(sqlFix1+`cb.bias = 'AT' AND `+sqlFix2, i, independentSuggestion.Start, independentSuggestion.End, independentSuggestion.QuantityFixes)
			}
		}
		var codons []string
		db.Select(&codons, `SELECT codon FROM (SELECT codon, pos FROM history ORDER BY step DESC) GROUP BY pos`)
		sequence = strings.Join(codons, "")
	}
	return sequence, nil
}
// FixCds fixes a CDS given the CDS sequence, a codon table, and a list of functions to solve for.
FixCds fixes a CDS given the CDS sequence, a codon table, and a list of functions to solve for.
// FixCds fixes a CDS given the CDS sequence a codon table and a list of functions to solve for .
func FixCds(sqlitePath string, sequence string, codontable CodonTable, problematicSequenceFuncs []func(string, chan DnaSuggestion, *sync.WaitGroup)) (string, error) {
	var db *sqlx.DB
	db = sqlx.MustConnect("sqlite3", sqlitePath)
	createMemoryDbSql := `
	CREATE TABLE codon (
		codon TEXT PRIMARY KEY,
		aa TEXT
	);
	CREATE TABLE seq (
		pos INT PRIMARY KEY
	);
	CREATE TABLE history (
		pos INTEGER REFERENCES seq(pos),
		codon TEXT NOT NULL REFERENCES codon(codon),
		step INT
	);
	-- Weights are set on a per position basis for codon harmonization at a later point
	CREATE TABLE weights (
		pos INTEGER REFERENCES seq(pos),
		codon TEXT NOT NULL REFERENCES codon(codon),
		weight INTEGER
	);
	CREATE TABLE codonbias (
		fromcodon TEXT REFERENCES codon(codon),
		tocodon TEXT REFERENCES codon(codon),
		gcbias TEXT
	);
	CREATE TABLE suggestedfix (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		step INTEGER,
		start INTEGER REFERENCES seq(pos),
		end INTEGER REFERENCES seq(pos),
		gcbias TEXT,
		quantityfixes INTEGER,
		suggestiontype TEXT
	);
`
	db.MustExec(createMemoryDbSql)
	weightTable := make(map[string]int)
	codonInsert := `INSERT INTO codon(codon, aa) VALUES (?, ?)`
	for _, aminoAcid := range codontable.AminoAcids {
		for _, codon := range aminoAcid.Codons {
			db.MustExec(codonInsert, codon.Triplet, aminoAcid.Letter)
			weightTable[codon.Triplet] = codon.Weight
			codonBias := strings.Count(codon.Triplet, "G") + strings.Count(codon.Triplet, "C")
			for _, toCodon := range aminoAcid.Codons {
				if codon.Triplet != toCodon.Triplet {
					toCodonBias := strings.Count(toCodon.Triplet, "G") + strings.Count(toCodon.Triplet, "C")
					switch {
					case codonBias == toCodonBias:
						db.MustExec(`INSERT INTO codonbias(fromcodon, tocodon, gcbias) VALUES (?, ?, ?)`, codon.Triplet, toCodon.Triplet, "NA")
					case codonBias > toCodonBias:
						db.MustExec(`INSERT INTO codonbias(fromcodon, tocodon, gcbias) VALUES (?, ?, ?)`, codon.Triplet, toCodon.Triplet, "AT")
					case codonBias < toCodonBias:
						db.MustExec(`INSERT INTO codonbias(fromcodon, tocodon, gcbias) VALUES (?, ?, ?)`, codon.Triplet, toCodon.Triplet, "GC")
					}
				}
			}
		}
	}
	pos := 0
	for i := 0; i < len(sequence)-3; i = i + 3 {
		codon := sequence[i : i+3]
		db.MustExec(`INSERT INTO seq(pos) VALUES (?)`, pos)
		db.MustExec(`INSERT INTO history(pos, codon, step) VALUES (?, ?, 0)`, pos, codon)
		db.MustExec(`INSERT INTO weights(pos, codon, weight) VALUES (?,?,?)`, pos, codon, weightTable[codon])
		pos++
	}
	var err error
	for i := 1; i < 100; i++ {
		suggestions := findProblems(sequence, problematicSequenceFuncs)
		if len(suggestions) == 0 {
			break
		}
		for _, suggestion := range suggestions { 
			_, err = db.Exec(`INSERT INTO suggestedfix(step, start, end, gcbias, quantityfixes, suggestiontype) VALUES (?, ?, ?, ?, ?, ?)`, i, suggestion.Start, suggestion.End, suggestion.Bias, suggestion.QuantityFixes, suggestion.SuggestionType)
			if err != nil {
				return sequence, err
			}
		}
		sqlFix1 := `INSERT INTO history
		            (codon,
		             pos,
		             step)
		SELECT t.codon,
		       t.pos,
		       ? AS step
		FROM   (SELECT cb.tocodon AS codon,
		               s.pos      AS pos
		        FROM   seq AS s
		               JOIN history AS h
		                 ON h.pos = s.pos
		               JOIN weights AS w
		                 ON w.pos = s.pos
		               JOIN codon AS c
		                 ON h.codon = c.codon
		               JOIN codonbias AS cb
		                 ON cb.fromcodon = c.codon
		        WHERE `
		sqlFix2 := ` s.pos >= ?
		               AND s.pos <= ?
		               AND h.codon != cb.tocodon
		        ORDER  BY w.weight) AS t
		GROUP  BY t.pos
		LIMIT  ?; `
		independentSuggestions := []DnaSuggestion{}
		db.Select(&independentSuggestions, `SELECT * FROM suggestedfix WHERE step = ?`, i)
		for _, independentSuggestion := range independentSuggestions {
			switch independentSuggestion.Bias {
			case "NA":
				db.MustExec(sqlFix1+sqlFix2, i, independentSuggestion.Start, independentSuggestion.End, independentSuggestion.QuantityFixes)
			case "GC":
				db.MustExec(sqlFix1+`cb.bias = 'GC' AND `+sqlFix2, i, independentSuggestion.Start, independentSuggestion.End, independentSuggestion.QuantityFixes)
			case "AT":
				db.MustExec(sqlFix1+`cb.bias = 'AT' AND `+sqlFix2, i, independentSuggestion.Start, independentSuggestion.End, independentSuggestion.QuantityFixes)
			}
		}
		var codons []string
		db.Select(&codons, `SELECT codon FROM (SELECT codon, pos FROM history ORDER BY step DESC) GROUP BY pos`)
		sequence = strings.Join(codons, "")
	}
	return sequence, nil
}
func FixCds ( sqlitePath string , sequence string , codontable CodonTable , problematicSequenceFuncs [ ] func ( string , chan DnaSuggestion , * sync . WaitGroup ) ) ( string , error ) { var db * sqlx . DB db = sqlx . MustConnect ( " " , sqlitePath ) createMemoryDbSql := `
	CREATE TABLE codon (
		codon TEXT PRIMARY KEY,
		aa TEXT
	);

	CREATE TABLE seq (
		pos INT PRIMARY KEY
	);

	CREATE TABLE history (
		pos INTEGER REFERENCES seq(pos),
		codon TEXT NOT NULL REFERENCES codon(codon),
		step INT
	);

	-- Weights are set on a per position basis for codon harmonization at a later point
	CREATE TABLE weights (
		pos INTEGER REFERENCES seq(pos),
		codon TEXT NOT NULL REFERENCES codon(codon),
		weight INTEGER
	);

	CREATE TABLE codonbias (
		fromcodon TEXT REFERENCES codon(codon),
		tocodon TEXT REFERENCES codon(codon),
		gcbias TEXT
	);

	CREATE TABLE suggestedfix (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		step INTEGER,
		start INTEGER REFERENCES seq(pos),
		end INTEGER REFERENCES seq(pos),
		gcbias TEXT,
		quantityfixes INTEGER,
		suggestiontype TEXT
	);
` db . MustExec ( createMemoryDbSql ) weightTable := make ( map [ string ] int ) codonInsert := `INSERT INTO codon(codon, aa) VALUES (?, ?)` for _ , aminoAcid := range codontable . AminoAcids { for _ , codon := range aminoAcid . Codons { db . MustExec ( codonInsert , codon . Triplet , aminoAcid . Letter ) weightTable [ codon . Triplet ] = codon . Weight codonBias := strings . Count ( codon . Triplet , " " ) + strings . Count ( codon . Triplet , " " ) for _ , toCodon := range aminoAcid . Codons { if codon . Triplet != toCodon . Triplet { toCodonBias := strings . Count ( toCodon . Triplet , " " ) + strings . Count ( toCodon . Triplet , " " ) switch { case codonBias == toCodonBias : db . MustExec ( `INSERT INTO codonbias(fromcodon, tocodon, gcbias) VALUES (?, ?, ?)` , codon . Triplet , toCodon . Triplet , " " ) case codonBias > toCodonBias : db . MustExec ( `INSERT INTO codonbias(fromcodon, tocodon, gcbias) VALUES (?, ?, ?)` , codon . Triplet , toCodon . Triplet , " " ) case codonBias < toCodonBias : db . MustExec ( `INSERT INTO codonbias(fromcodon, tocodon, gcbias) VALUES (?, ?, ?)` , codon . Triplet , toCodon . Triplet , " " ) } } } } } pos := 0 for i := 0 ; i < len ( sequence ) - 3 ; i = i + 3 { codon := sequence [ i : i + 3 ] db . MustExec ( `INSERT INTO seq(pos) VALUES (?)` , pos ) db . MustExec ( `INSERT INTO history(pos, codon, step) VALUES (?, ?, 0)` , pos , codon ) db . MustExec ( `INSERT INTO weights(pos, codon, weight) VALUES (?,?,?)` , pos , codon , weightTable [ codon ] ) pos ++ } var err error for i := 1 ; i < 100 ; i ++ { suggestions := findProblems ( sequence , problematicSequenceFuncs ) if len ( suggestions ) == 0 { break } for _ , suggestion := range suggestions { _ , err = db . Exec ( `INSERT INTO suggestedfix(step, start, end, gcbias, quantityfixes, suggestiontype) VALUES (?, ?, ?, ?, ?, ?)` , i , suggestion . Start , suggestion . End , suggestion . Bias , suggestion . QuantityFixes , suggestion . SuggestionType ) if err != nil { return sequence , err } } sqlFix1 := `INSERT INTO history
		            (codon,
		             pos,
		             step)
		SELECT t.codon,
		       t.pos,
		       ? AS step
		FROM   (SELECT cb.tocodon AS codon,
		               s.pos      AS pos
		        FROM   seq AS s
		               JOIN history AS h
		                 ON h.pos = s.pos
		               JOIN weights AS w
		                 ON w.pos = s.pos
		               JOIN codon AS c
		                 ON h.codon = c.codon
		               JOIN codonbias AS cb
		                 ON cb.fromcodon = c.codon
		        WHERE ` sqlFix2 := ` s.pos >= ?
		               AND s.pos <= ?
		               AND h.codon != cb.tocodon
		        ORDER  BY w.weight) AS t
		GROUP  BY t.pos
		LIMIT  ?; ` independentSuggestions := [ ] DnaSuggestion { } db . Select ( & independentSuggestions , `SELECT * FROM suggestedfix WHERE step = ?` , i ) for _ , independentSuggestion := range independentSuggestions { switch independentSuggestion . Bias { case " " : db . MustExec ( sqlFix1 + sqlFix2 , i , independentSuggestion . Start , independentSuggestion . End , independentSuggestion . QuantityFixes ) case " " : db . MustExec ( sqlFix1 + `cb.bias = 'GC' AND ` + sqlFix2 , i , independentSuggestion . Start , independentSuggestion . End , independentSuggestion . QuantityFixes ) case " " : db . MustExec ( sqlFix1 + `cb.bias = 'AT' AND ` + sqlFix2 , i , independentSuggestion . Start , independentSuggestion . End , independentSuggestion . QuantityFixes ) } } var codons [ ] string db . Select ( & codons , `SELECT codon FROM (SELECT codon, pos FROM history ORDER BY step DESC) GROUP BY pos` ) sequence = strings . Join ( codons , " " ) } return sequence , nil }
FixCds fixes a CDS given the CDS sequence, a codon table, and a list of functions to solve for.
FixCds fixes a CDS given the CDS sequence a codon table and a list of functions to solve for .
// Insert codons // Insert seq and history // For a maximum of 1000 iterations, see if we can do better // If there are no suggestions, break the iteration! // if you want to add overlaps, add suggestionIndex // First, let's insert the suggestions that we found using our problematicSequenceFuncs // The following statements are the magic sauce that makes this all worthwhile. // Parameters: step, gcbias, start, end, quantityfix