{"id":16976162,"url":"https://github.com/gata-bio/affine-gaps","last_synced_at":"2025-04-12T01:34:59.433Z","repository":{"id":241068189,"uuid":"804197663","full_name":"gata-bio/affine-gaps","owner":"gata-bio","description":"Less-wrong single-file Numba-accelerated Python implementation of Gotoh affine gap penalty extensions for the Needleman–Wunsch, Smith-Waterman, and Levenshtein algorithms for sequence alignment","archived":false,"fork":false,"pushed_at":"2024-08-14T16:49:57.000Z","size":100,"stargazers_count":8,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-16T03:38:11.687Z","etag":null,"topics":["bioinformatics","jit","levenshtein-algorithm","levenshtein-distance","needleman-wunsch","protein","protein-sequences","search","sequence-alignment","smith-waterman","string-search"],"latest_commit_sha":null,"homepage":"https://github.com/ashvardanian/stringzilla","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gata-bio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-05-22T06:22:36.000Z","updated_at":"2025-01-05T15:04:46.000Z","dependencies_parsed_at":"2024-05-22T08:40:31.694Z","dependency_job_id":"3c892217-dce7-4b33-a873-8dc465d09982","html_url":"https://github.com/gata-bio/affine-gaps","commit_stats":null,"previous_names":["ashvardanian/affine-gaps","gata-bio/affine-gaps"],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gata-bio%2Faffine-gaps","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gata-bio%2Faffine-gaps/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gata-bio%2Faffine-gaps/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gata-bio%2Faffine-gaps/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gata-bio","download_url":"https://codeload.github.com/gata-bio/affine-gaps/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239845310,"owners_count":19706590,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bioinformatics","jit","levenshtein-algorithm","levenshtein-distance","needleman-wunsch","protein","protein-sequences","search","sequence-alignment","smith-waterman","string-search"],"created_at":"2024-10-14T01:25:09.952Z","updated_at":"2025-04-12T01:34:59.418Z","avatar_url":"https://github.com/gata-bio.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Affine Gaps Thumbnail](https://github.com/ashvardanian/ashvardanian/blob/master/repositories/affine-gaps.jpg?raw=true)\n\n__Affine Gaps__ is a __less-wrong__ single-file Numba-accelerated Python implementation of Osamu Gotoh affine gap penalty extensions 1982 [paper](https://doc.aporc.org/attach/Course001Papers/gotoh1982.pdf) for the Needleman-Wunsch and Smith-Waterman algorithms often used for global and local sequence alignment in Bioinformatics.\nThanks to the Numba JIT compiler, it's also competitive in terms of performance.\nBut if you want to go even faster and need more hardware-accelerated string operations, check out [StringZilla](https://github.com/ashvardanian/stringzilla) 🦖\n\n## Less Wrong\n\nAs reported in the \"Are all global alignment algorithms and implementations correct?\" [paper](https://www.biorxiv.org/content/10.1101/031500v1.full.pdf) by Tomas Flouri, Kassian Kobert, Torbjørn Rognes, and Alexandros Stamatakis:\n\n\u003e In 1982 Gotoh presented an improved algorithm with lower time complexity. \n\u003e Gotoh’s algorithm is frequently cited...\n\u003e While implementing the algorithm, we discovered two mathematical mistakes in Gotoh’s paper that induce sub-optimal sequence alignments.\n\u003e First, there are minor indexing mistakes in the dynamic programming algorithm which become apparent immediately when implementing the procedure.\n\u003e Hence, we report on these for the sake of completeness.\n\u003e Second, there is a more profound problem with the dynamic programming matrix initialization.\n\u003e This initialization issue can easily be missed and find its way into actual implementations.\n\u003e This error is also present in standard text books.\n\u003e Namely, the widely used books by Gusfield and Waterman.\n\u003e To obtain an initial estimate of the extent to which this error has been propagated, we scrutinized freely available undergraduate lecture slides.\n\u003e We found that 8 out of 31 lecture slides contained the mistake, while 16 out of 31 simply omit parts of the initialization, thus giving an incomplete description of the algorithm.\n\u003e Finally, by inspecting ten source codes and running respective tests, we found that five implementations were incorrect.\n\nDuring my exploration of exiting implementations, I've noticed several bugs:\n\n- several libraries initialize the header row/columns of penalty matrices with ±∞, causing overflows on the first iteration.\n- initialize matrices to zeros, ignoring the first gap opening cost.\n- combining opening and expansion costs where only the opening cost should be applied.\n- even the most correct `needle` from EMBOSS uses `float` representation, which would obviously be numerically unstable on very long sequences.\n\n## Installation\n\nEven without installing Python, you can just use `uv` to get the latest version of the library:\n\n```bash\n$ uv tool install git+https://github.com/ashvardanian/affine-gaps.git\n$ affine-gaps --help\n```\n\nAlternatively, you can install it using `pip`:\n\n```bash\n$ pip install git+https://github.com/ashvardanian/affine-gaps.git\n$ affine-gaps --help\n```\n\n## Using the Library\n\nTo obtain the alignment of two sequences, use the `needleman_wunsch_gotoh_alignment` function.\n\n```python\nfrom affine_gaps import needleman_wunsch_gotoh_alignment\n\ninsulin = \"GIVEQCCTSICSLYQLENYCN\"\nglucagon = \"HSQGTFTSDYSKYLDSRAEQDFV\"\naligned_insulin, aligned_glucagon, aligned_score = needleman_wunsch_gotoh_alignment(insulin, glucagon)\n\nprint(\"Alignment 1:\", aligned_insulin)  # GI-V---EQCC-TSICSLY---QL-ENYCN-\nprint(\"Alignment 2:\", aligned_glucagon) # --D-FVHSQGTFTSDYSKYLDSRAEQDF--V\nprint(\"Score:\", aligned_score)          # 41\n```\n\nIf you only need the alignment score, you can use the `needleman_wunsch_gotoh_score` function, which uses less memory and works faster.\n\n```python\nfrom affine_gaps import needleman_wunsch_gotoh_score\n\nscore = needleman_wunsch_gotoh_score(insulin, glucagon)\n\nprint(\"Score:\", score)\n```\n\nBy default, a BLOSUM62 substitution matrix is used.\nYou can specify a different substitution matrix by passing it as an argument.\n\n```python\nfrom numpy import np\n\nalphabet = \"ARNDCQEGHILKMFPSTWYVBZX\"\nsubstitutions = np.zeros((len(alphabet), len(alphabet)), dtype=np.int8)\nsubstitutions.fill(-1)\nnp.fill_diagonal(substitutions, 1)\n\naligned_insulin, aligned_glucagon, aligned_score = needleman_wunsch_gotoh_alignment(\n    insulin, glucagon,\n    substitution_alphabet=alphabet,\n    substitution_matrix=substitutions,\n    gap_opening=-2,\n    gap_extension=-1,\n)\n```\n\nThat is similar to the following usage example of BioPython:\n\n```python\nfrom Bio import Align\nfrom Bio.Align import substitution_matrices\n\naligner = Align.PairwiseAligner(mode=\"global\")\naligner.substitution_matrix = substitution_matrices.load(\"BLOSUM62\")\naligner.open_gap_score = open_gap_score\naligner.extend_gap_score = extend_gap_score\n```\n\n## Using the Command Line Interface\n\nTo compute the optimal global alignment of insulin and glucagon sequences with (5x-scaled) BLOSUM62 substitution matrix through CLI:\n\n```bash\n$ affine-gaps GIVEQCCTSICSLYQLENYCN HSQGTFTSDYSKYLDSRAEQDFV\n\u003e\n\u003e Sequence 1: GIVEQCCTSICSLYQLENYCN\n\u003e Sequence 2: HSQGTFTSDYSKYLDSRAEQDFV\n\u003e\n\u003e Alignment 1: GIVEQCCTSICSLY---QL-ENYCN-\n\u003e Alignment 2: GTF----TSDYSKYLDSRAEQDF--V\n\u003e Score:       22\n```\n\nTo compute the local alignment of insulin and glucagon sequences through CLI:\n\n```bash\n\n$ affine-gaps GIVEQCCTSICSLYQLENYCN HSQGTFTSDYSKYLDSRAEQDFV --local\n\u003e \n\u003e Sequence 1: GIVEQCCTSICSLYQLENYCN\n\u003e Sequence 2: HSQGTFTSDYSKYLDSRAEQDFV\n\u003e \n\u003e Alignment 1: TSICSLYQLEN\n\u003e Alignment 2: TSDYSKY-LDS\n\u003e Score:       80\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgata-bio%2Faffine-gaps","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgata-bio%2Faffine-gaps","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgata-bio%2Faffine-gaps/lists"}