{"id":16834703,"url":"https://github.com/jeffail/spiril","last_synced_at":"2025-08-24T06:36:19.090Z","repository":{"id":79520361,"uuid":"113741895","full_name":"Jeffail/spiril","owner":"Jeffail","description":"Rust library for genetic algorithms","archived":false,"fork":false,"pushed_at":"2018-05-16T08:32:42.000Z","size":12,"stargazers_count":29,"open_issues_count":1,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-11T04:35:00.188Z","etag":null,"topics":["evolutionary","genetic","rust"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Jeffail.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":"2017-12-10T10:44:18.000Z","updated_at":"2024-08-28T16:11:28.000Z","dependencies_parsed_at":"2023-03-07T05:45:57.020Z","dependency_job_id":null,"html_url":"https://github.com/Jeffail/spiril","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jeffail%2Fspiril","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jeffail%2Fspiril/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jeffail%2Fspiril/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jeffail%2Fspiril/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Jeffail","download_url":"https://codeload.github.com/Jeffail/spiril/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248345258,"owners_count":21088231,"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":["evolutionary","genetic","rust"],"created_at":"2024-10-13T12:07:28.632Z","updated_at":"2025-04-11T04:35:02.071Z","avatar_url":"https://github.com/Jeffail.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"Spiril\n======\n\nSpiril is an implementation of a genetic algorithm for obtaining optimum\nvariables (genetics) for a task through mutation and natural selection.\n\nThe API allows you to specify an initial group of units, which will act as\nthe original parents of all subsequent units. Unit types implement a fitness\nfunction and a breed function for introducing new genetic combinations and\nmutations into subsequent generations.\n\nFitnesses can be calculated across a population using parallel threads.\n\n## Sudoku example\n\n``` rust\nextern crate spiril;\nextern crate rand;\n\nuse spiril::unit::Unit;\nuse spiril::population::Population;\nuse rand::{StdRng, SeedableRng, Rng};\n\nstruct SudokuUnit {\n    sudoku: Vec\u003cusize\u003e, // 9x9 grid\n    answer: Vec\u003cusize\u003e, // 9x9 grid\n}\n\nimpl Unit for SudokuUnit {\n    fn fitness(\u0026self) -\u003e f64 {\n        let mut score = 1.0_f64;\n\n        for i in 0..9 {\n            let mut seen_row: [usize; 9] = [0, 0, 0, 0, 0, 0, 0, 0, 0];\n            let mut seen_col: [usize; 9] = [0, 0, 0, 0, 0, 0, 0, 0, 0];\n            let mut seen_sqr: [usize; 9] = [0, 0, 0, 0, 0, 0, 0, 0, 0];\n\n            for j in 0..9 {\n                seen_row[self.answer[i * 9 + j] - 1] += 1;\n                seen_col[self.answer[i + 9 * j] - 1] += 1;\n\n                let sqr_index = ((i % 3) * 3) + (((i / 3) % 3) * 27) + (9 * (j / 3)) + j % 3;\n                seen_sqr[self.answer[sqr_index] - 1] += 1;\n            }\n\n            seen_row\n                .iter()\n                .chain(seen_col.iter())\n                .chain(seen_sqr.iter())\n                .map(|x| if *x == 0 {\n                    // score -= (1.0 / 729.0);\n                    score *= 0.9;\n                })\n                .last();\n        }\n\n        score\n    }\n\n    fn breed_with(\u0026self, other: \u0026SudokuUnit) -\u003e SudokuUnit {\n        // Even rows taken from self, odd rows taken from other.\n        // Mutations applied at random.\n        let mut new_unit: SudokuUnit = SudokuUnit {\n            sudoku: self.sudoku.clone(),\n            answer: self.answer.clone(),\n        };\n\n        (0_usize..81_usize)\n            .filter(|x| self.sudoku[*x] == 0)\n            .map(|x| {\n                if rand::thread_rng().gen_range(0, 1) == 1 {\n                    new_unit.answer[x] = other.answer[x];\n                }\n                new_unit.answer[x]\n            })\n            .last();\n\n        loop {\n            let i = rand::thread_rng().gen_range(0, 81);\n            if self.sudoku[i] == 0 {\n                new_unit.answer[i] = rand::thread_rng().gen_range(1, 10);\n                break;\n            }\n        }\n\n        new_unit\n    }\n}\n\nfn main() {\n    let test_doku: Vec\u003cusize\u003e = vec![\n        7, 2, 6,   0, 9, 3,   8, 1, 5,\n        3, 0, 5,   7, 2, 8,   9, 0, 6,\n        4, 8, 0,   6, 0, 1,   2, 3, 7,\n\n        8, 5, 2,   1, 4, 0,   6, 9, 3,\n        0, 7, 3,   9, 8, 5,   1, 2, 4,\n        9, 4, 1,   0, 6, 2,   0, 5, 8,\n\n        1, 9, 0,   8, 3, 0,   5, 7, 2,\n        5, 6, 7,   2, 1, 4,   3, 8, 0,\n        2, 0, 8,   5, 0, 9,   4, 6, 1,\n    ];\n\n    let seed: \u0026[_] = \u0026[0];\n    let mut init_rng: StdRng = SeedableRng::from_seed(seed);\n    let units: Vec\u003cSudokuUnit\u003e = (0..1000)\n        .map(|_| {\n            SudokuUnit {\n                sudoku: test_doku.clone(),\n                answer: test_doku\n                    .clone()\n                    .iter()\n                    .map(|x| if *x == 0 {\n                        init_rng.gen_range(1, 10)\n                    } else {\n                        *x\n                    })\n                    .collect(),\n            }\n        })\n        .collect();\n\n    assert_eq!(Population::new(units)\n        .set_size(1000)\n        .set_breed_factor(0.3)\n        .set_survival_factor(0.5)\n        .epochs_parallel(5000, 4) // 4 CPU cores\n        .finish()\n        .first()\n        .unwrap()\n        .fitness(), 1.0);\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeffail%2Fspiril","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjeffail%2Fspiril","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeffail%2Fspiril/lists"}